diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index d442f104..5ba7197b 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -4,6 +4,7 @@ on: pull_request: branches: - master + - next paths: - '.github/workflows/android.yml' - 'android/**' @@ -11,6 +12,7 @@ on: push: branches: - master + - next concurrency: group: ${{ github.ref }}-android diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index e5e7030f..f9085a40 100644 --- a/.github/workflows/ios.yml +++ b/.github/workflows/ios.yml @@ -4,6 +4,7 @@ on: pull_request: branches: - master + - next paths: - '.github/workflows/ios.yml' - 'ios/**' @@ -11,6 +12,7 @@ on: push: branches: - master + - next concurrency: group: ${{ github.ref }}-ios diff --git a/README.md b/README.md index 3e98f989..b680efa7 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,10 @@ [![iOS Build](https://github.com/callstack/react-native-pager-view/actions/workflows/ios.yml/badge.svg)](https://github.com/callstack/react-native-pager-view/actions/workflows/ios.yml) [![Android Build](https://github.com/callstack/react-native-pager-view/actions/workflows/android.yml/badge.svg)](https://github.com/callstack/react-native-pager-view/actions/workflows/android.yml) -This component allows the user to swipe left and right through pages of data. Under the hood it is using the native [Android ViewPager](https://developer.android.com/reference/android/support/v4/view/ViewPager) and the [iOS UIPageViewController](https://developer.apple.com/documentation/uikit/uipageviewcontroller) implementations. [See it in action!](https://github.com/callstack/react-native-pager-view#preview) +PagerView allows the user to swipe left and right through pages of data. +It leverages the native [Android ViewPager2](https://developer.android.com/jetpack/androidx/releases/viewpager2) +and [iOS UIScrollView](https://developer.apple.com/documentation/uikit/uiscrollview) under the hood. +[See it in action!](https://github.com/callstack/react-native-pager-view#preview)

@@ -17,22 +20,80 @@ This component allows the user to swipe left and right through pages of data. Un
-## Versions +## Getting started -| 4.x | 5.x | -| ---------- | ----------- | -| iOS | iOS support | -| ViewPager1 | ViewPager2 | +Install the library with: -## Migration +```sh +yarn add react-native-pager-view +``` -In version **6.x** support for `transitionStyle` property has been dropped. More information [here](https://github.com/callstack/react-native-pager-view/blob/master/MIGRATION.md). +or: -`"@react-native-community/viewpager"` library has been changed to `react-native-pager-view`. Here you can find more information, how to migrate pager view to the latest [version](https://github.com/callstack/react-native-pager-view/blob/master/MIGRATION.md) +```sh +npm install react-native-pager-view +``` -## Getting started +## Migration from `@react-native-community/viewpager` + +The `@react-native-community/viewpager` library has been moved and now lives here, in the `react-native-pager-view` repo. +[Here](https://github.com/callstack/react-native-pager-view/blob/master/MIGRATION.md) you can find +more information on how to migrate PagerView to the latest version. + +## Versions & compatibility + +The underlying iOS/Android native implementations of PagerView have changed over the years. +Here's an overview of the implementation details throughout the library's lifespan: + +| | `1.x.x` | `2.x.x` | `5.0.8` | `7.x.x` | +| ------- | ----------- | ---------------------- | ---------------------- | -------------- | +| iOS | ❌ | `UIPageViewController` | `UIPageViewController` | `UIScrollView` | +| Android | `ViewPager` | `ViewPager` | `ViewPager2` | `ViewPager2` | + +### Legacy iOS implementation support (`UIPageViewController`) + +As per the table above, the iOS implementation of this library has been rewritten to use +[`UIScrollView`](https://developer.apple.com/documentation/uikit/uiscrollview) over +[`UIPageViewController`](https://developer.apple.com/documentation/uikit/uipageviewcontroller). + +For backwards-compatibility purposes, the old iOS implementation is still supported, however — simply pass `true` to +the `useLegacy` boolean prop to switch the used implementation back to `UIPageViewController`. + +### Other notes + +In version **6.x.x** the support for the iOS `transitionStyle` property has been dropped. +More information [here](https://github.com/callstack/react-native-pager-view/blob/master/MIGRATION.md). + +## New architecture support (Fabric) + +This library supports both architectures — Paper and Fabric! -`yarn add react-native-pager-view` +To properly migrate to the new architecture and enable it in your app consult the newest +[docs](https://reactnative.dev/docs/new-architecture-app-intro). + +From the perspective of PagerView, the steps required to make the library work with Fabric are as follows: + +### iOS + +Install pods the usual way, with the `RCT_NEW_ARCH_ENABLED` flag set, e.g.: + +```sh +cd ios && RCT_NEW_ARCH_ENABLED=1 bundle exec pod install +``` + +### Android + +In the `android/gradle.properties` file, set `newArchEnabled` to `true` and build the app, e.g.: + +```sh +yarn android +``` + +If you have issues running the Android build, you can try generating the Codegen files before the build using: + +```sh +cd android && ./gradlew generateCodegenArtifactsFromSchema +``` ## Linking @@ -133,7 +194,7 @@ const styles = StyleSheet.create({ ## Advanced usage -For advanced usage please take a look into our [example project](https://github.com/callstack/react-native-pager-view/blob/master/example/src/BasicPagerViewExample.tsx) +For advanced usage please take a look into our [example project](https://github.com/callstack/react-native-pager-view/blob/master/example/src/BasicPagerViewExample.tsx). ## API @@ -188,7 +249,7 @@ requestAnimationFrame(() => refPagerView.current?.setPage(index)); ## Reanimated onPageScroll handler -An example can be found [here](https://github.com/callstack/react-native-pager-view/blob/master/example/src/ReanimatedOnPageScrollExample.tsx) +An example can be found [here](https://github.com/callstack/react-native-pager-view/blob/master/example/src/ReanimatedOnPageScrollExample.tsx). #### Instructions diff --git a/android/src/fabric/java/com/reactnativepagerview/LEGACY_PagerViewViewManager.kt b/android/src/fabric/java/com/reactnativepagerview/LEGACY_PagerViewViewManager.kt new file mode 100644 index 00000000..b202b4c1 --- /dev/null +++ b/android/src/fabric/java/com/reactnativepagerview/LEGACY_PagerViewViewManager.kt @@ -0,0 +1,17 @@ +package com.reactnativepagerview + +import com.facebook.react.uimanager.ViewGroupManager +import android.widget.FrameLayout +import com.facebook.react.module.annotations.ReactModule +import com.facebook.react.uimanager.ThemedReactContext + +// Note: The LEGACY_ variant is an iOS-only feature and the related Android files +// are only included because of and relevant to auxiliary processes, like Codegen. +@ReactModule(name = LEGACY_PagerViewViewManagerImpl.NAME) +class LEGACY_PagerViewViewManager : ViewGroupManager() { + override fun getName() = LEGACY_PagerViewViewManagerImpl.NAME + + override fun createViewInstance(context: ThemedReactContext): FrameLayout { + throw Error("LEGACY_RNCViewPager is an iOS-only feature") + } +} diff --git a/android/src/fabric/java/com/reactnativepagerview/PagerViewViewManager.kt b/android/src/fabric/java/com/reactnativepagerview/PagerViewViewManager.kt index e1c5ca44..72a6b4ea 100644 --- a/android/src/fabric/java/com/reactnativepagerview/PagerViewViewManager.kt +++ b/android/src/fabric/java/com/reactnativepagerview/PagerViewViewManager.kt @@ -164,6 +164,11 @@ class PagerViewViewManager : ViewGroupManager(), RNCViewPa return } + @ReactProp(name = "useLegacy") + override fun setUseLegacy(view: NestedScrollableHost?, value: Boolean) { + return + } + fun goTo(root: NestedScrollableHost?, selectedPage: Int, scrollWithAnimation: Boolean) { if (root == null) { return diff --git a/android/src/main/java/com/reactnativepagerview/LEGACY_PagerViewViewManagerImpl.kt b/android/src/main/java/com/reactnativepagerview/LEGACY_PagerViewViewManagerImpl.kt new file mode 100644 index 00000000..7cecdc82 --- /dev/null +++ b/android/src/main/java/com/reactnativepagerview/LEGACY_PagerViewViewManagerImpl.kt @@ -0,0 +1,7 @@ +package com.reactnativepagerview + +// Note: The LEGACY_ variant is an iOS-only feature and the related Android files +// are only included because of and relevant to auxiliary processes, like Codegen. +object LEGACY_PagerViewViewManagerImpl { + const val NAME = "LEGACY_RNCViewPager" +} diff --git a/android/src/main/java/com/reactnativepagerview/PagerViewViewPackage.kt b/android/src/main/java/com/reactnativepagerview/PagerViewViewPackage.kt index 194bf0aa..b09b6e1c 100644 --- a/android/src/main/java/com/reactnativepagerview/PagerViewViewPackage.kt +++ b/android/src/main/java/com/reactnativepagerview/PagerViewViewPackage.kt @@ -12,6 +12,6 @@ class PagerViewPackage : ReactPackage { } override fun createViewManagers(reactContext: ReactApplicationContext): List> { - return listOf(PagerViewViewManager()) + return listOf(PagerViewViewManager(), LEGACY_PagerViewViewManager()) } } diff --git a/android/src/paper/java/com/reactnativepagerview/LEGACY_PagerViewViewManager.kt b/android/src/paper/java/com/reactnativepagerview/LEGACY_PagerViewViewManager.kt new file mode 100644 index 00000000..b202b4c1 --- /dev/null +++ b/android/src/paper/java/com/reactnativepagerview/LEGACY_PagerViewViewManager.kt @@ -0,0 +1,17 @@ +package com.reactnativepagerview + +import com.facebook.react.uimanager.ViewGroupManager +import android.widget.FrameLayout +import com.facebook.react.module.annotations.ReactModule +import com.facebook.react.uimanager.ThemedReactContext + +// Note: The LEGACY_ variant is an iOS-only feature and the related Android files +// are only included because of and relevant to auxiliary processes, like Codegen. +@ReactModule(name = LEGACY_PagerViewViewManagerImpl.NAME) +class LEGACY_PagerViewViewManager : ViewGroupManager() { + override fun getName() = LEGACY_PagerViewViewManagerImpl.NAME + + override fun createViewInstance(context: ThemedReactContext): FrameLayout { + throw Error("LEGACY_RNCViewPager is an iOS-only feature") + } +} diff --git a/example/android/app/src/main/java/com/pagerviewexample/MainActivity.java b/example/android/app/src/main/java/com/pagerviewexample/MainActivity.java index a9fb4371..454c5320 100644 --- a/example/android/app/src/main/java/com/pagerviewexample/MainActivity.java +++ b/example/android/app/src/main/java/com/pagerviewexample/MainActivity.java @@ -32,6 +32,9 @@ protected ReactActivityDelegate createReactActivityDelegate() { this, getMainComponentName(), // If you opted-in for the New Architecture, we enable the Fabric Renderer. - DefaultNewArchitectureEntryPoint.getFabricEnabled()); + DefaultNewArchitectureEntryPoint.getFabricEnabled() // fabricEnabled + // If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18). + // DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled // TODO: why has this been deleted? + ); } } diff --git a/example/ios/PagerViewExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/PagerViewExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/example/ios/PagerViewExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index a7ea1235..05bdad37 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -377,7 +377,7 @@ PODS: - glog - react-native-pager-view (7.0.0-rc.0): - React-Core - - react-native-safe-area-context (3.4.1): + - react-native-safe-area-context (4.7.4): - React-Core - React-NativeModulesApple (0.72.5): - hermes-engine @@ -491,7 +491,8 @@ PODS: - React-perflogger (= 0.72.5) - RNCMaskedView (0.1.11): - React - - RNGestureHandler (1.10.3): + - RNGestureHandler (2.13.4): + - RCT-Folly (= 2021.07.22.00) - React-Core - RNReanimated (3.5.4): - DoubleConversion @@ -522,9 +523,9 @@ PODS: - React-RCTText - ReactCommon/turbomodule/core - Yoga - - RNScreens (3.20.0): + - RNScreens (3.27.0): + - RCT-Folly (= 2021.07.22.00) - React-Core - - React-RCTImage - RNSVG (12.4.4): - React-Core - SocketRocket (0.6.1) @@ -751,7 +752,7 @@ SPEC CHECKSUMS: React-jsinspector: aef73cbd43b70675f572214d10fa438c89bf11ba React-logger: 2e4aee3e11b3ec4fa6cfd8004610bbb3b8d6cca4 react-native-pager-view: 563a43b511eea680f803ab4fb20bd7525fbde2cc - react-native-safe-area-context: 9e40fb181dac02619414ba1294d6c2a807056ab9 + react-native-safe-area-context: 2cd91d532de12acdb0a9cbc8d43ac72a8e4c897c React-NativeModulesApple: 797bc6078d566eef3fb3f74127e6e1d2e945a15f React-perflogger: cd8886513f68e1c135a1e79d20575c6489641597 React-RCTActionSheet: 726d2615ca62a77ce3e2c13d87f65379cdc73498 @@ -770,9 +771,9 @@ SPEC CHECKSUMS: React-utils: 7a9918a1ffdd39aba67835d42386f592ea3f8e76 ReactCommon: 91ece8350ebb3dd2be9cef662abd78b6948233c0 RNCMaskedView: 0e1bc4bfa8365eba5fbbb71e07fbdc0555249489 - RNGestureHandler: a479ebd5ed4221a810967000735517df0d2db211 + RNGestureHandler: 6e46dde1f87e5f018a54fe5d40cd0e0b942b49ee RNReanimated: ab2e96c6d5591c3dfbb38a464f54c8d17fb34a87 - RNScreens: 218801c16a2782546d30bd2026bb625c0302d70f + RNScreens: 3c2d122f5e08c192e254c510b212306da97d2581 RNSVG: ecd661f380a07ba690c9c5929c475a44f432d674 SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Yoga: 86fed2e4d425ee4c6eab3813ba1791101ee153c6 @@ -780,4 +781,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 3875acd7cb7e8f7782e244f1db71aa5f14571810 -COCOAPODS: 1.13.0 +COCOAPODS: 1.12.1 diff --git a/example/package.json b/example/package.json index cc026083..e851e822 100644 --- a/example/package.json +++ b/example/package.json @@ -16,10 +16,10 @@ "react": "18.2.0", "react-native": "0.72.5", "react-native-animated-pagination-dots": "^0.1.73", - "react-native-gesture-handler": "^1.9.0", + "react-native-gesture-handler": "2.13.4", "react-native-reanimated": "3.5.4", - "react-native-safe-area-context": "^3.1.9", - "react-native-screens": "~3.20.0", + "react-native-safe-area-context": "^4.4.1", + "react-native-screens": "3.27.0", "react-native-svg": "12.4.4", "react-native-tab-view": "^3.1.1" }, @@ -30,6 +30,7 @@ "@babel/core": "^7.20.0", "@babel/preset-env": "^7.20.0", "@babel/runtime": "^7.20.0", + "@types/jest": "^29.2.1", "@react-native/metro-config": "^0.72.11", "@tsconfig/react-native": "^3.0.0", "@types/react": "^18.0.24", diff --git a/example/src/App.tsx b/example/src/App.tsx index 16c0af4f..b54d8425 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -12,6 +12,7 @@ import { Alert, I18nManager, DevSettings, + Platform, } from 'react-native'; import { NavigationContainer, useNavigation } from '@react-navigation/native'; import { createStackNavigator } from '@react-navigation/stack'; @@ -33,6 +34,7 @@ import CoverflowExample from './tabView/CoverflowExample'; import ReanimatedOnPageScrollExample from './ReanimatedOnPageScrollExample'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; import { SafeAreaProvider } from 'react-native-safe-area-context'; +import { LegacyBasicPagerViewExample } from './LegacyBasicPagerViewExample'; const examples = [ { component: BasicPagerViewExample, name: 'Basic Example' }, @@ -65,6 +67,13 @@ const examples = [ { component: CoverflowExample, name: 'CoverflowExample' }, ]; +if (Platform.OS === 'ios') { + examples.unshift({ + component: LegacyBasicPagerViewExample, + name: '❌ Legacy Basic Example', + }); +} + function App() { const navigation = useNavigation(); return ( @@ -101,6 +110,9 @@ export function Navigation() { name="PagerView Example" component={App} options={{ + title: global?.nativeFabricUIManager + ? 'PagerView Example (Fabric)' + : 'PagerView Example', headerRight: () => (