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 @@
[](https://github.com/callstack/react-native-pager-view/actions/workflows/ios.yml)
[](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: () => (
diff --git a/example/src/LegacyBasicPagerViewExample.tsx b/example/src/LegacyBasicPagerViewExample.tsx
new file mode 100644
index 00000000..eeb3c91e
--- /dev/null
+++ b/example/src/LegacyBasicPagerViewExample.tsx
@@ -0,0 +1,70 @@
+import React, { useMemo } from 'react';
+import { StyleSheet, View, SafeAreaView, Animated, Text } from 'react-native';
+
+import PagerView from 'react-native-pager-view';
+
+import { LikeCount } from './component/LikeCount';
+import { NavigationPanel } from './component/NavigationPanel';
+import { useNavigationPanel } from './hook/useNavigationPanel';
+
+const AnimatedPagerView = Animated.createAnimatedComponent(PagerView);
+
+export function LegacyBasicPagerViewExample() {
+ const { ref, ...navigationPanel } = useNavigationPanel();
+
+ return (
+
+
+ {useMemo(
+ () =>
+ navigationPanel.pages.map((page, index) => (
+
+
+ {`page number ${index}`}
+
+ )),
+ [navigationPanel.pages]
+ )}
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: 'white',
+ },
+ image: {
+ width: 300,
+ height: 200,
+ padding: 20,
+ },
+ PagerView: {
+ flex: 1,
+ },
+});
diff --git a/example/src/NestPagerView.tsx b/example/src/NestPagerView.tsx
index 6aefd7ba..5968129e 100644
--- a/example/src/NestPagerView.tsx
+++ b/example/src/NestPagerView.tsx
@@ -22,7 +22,7 @@ export function NestPagerView() {
@@ -43,7 +43,7 @@ export function NestPagerView() {
@@ -51,7 +51,7 @@ export function NestPagerView() {
@@ -78,7 +78,7 @@ export function NestPagerView() {
@@ -89,7 +89,7 @@ export function NestPagerView() {
@@ -112,8 +112,5 @@ const styles = StyleSheet.create({
PagerView: {
flex: 1,
},
- page: {
- flex: 1,
- },
title: { fontSize: 22, paddingVertical: 10 },
});
diff --git a/example/src/PaginationDotsExample.tsx b/example/src/PaginationDotsExample.tsx
index 1093b9fc..6bba8a61 100644
--- a/example/src/PaginationDotsExample.tsx
+++ b/example/src/PaginationDotsExample.tsx
@@ -175,7 +175,6 @@ const styles = StyleSheet.create({
},
progressContainer: { flex: 0.1, backgroundColor: '#63a4ff' },
center: {
- flex: 1,
justifyContent: 'center',
alignItems: 'center',
alignContent: 'center',
diff --git a/example/yarn.lock b/example/yarn.lock
index 1c33fd87..efb1c289 100644
--- a/example/yarn.lock
+++ b/example/yarn.lock
@@ -1347,6 +1347,13 @@
dependencies:
jest-get-type "^29.4.3"
+"@jest/expect-utils@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6"
+ integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==
+ dependencies:
+ jest-get-type "^29.6.3"
+
"@jest/expect@^29.5.0":
version "29.5.0"
resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.5.0.tgz#80952f5316b23c483fbca4363ce822af79c38fba"
@@ -1966,6 +1973,14 @@
dependencies:
"@types/istanbul-lib-report" "*"
+"@types/jest@^29.2.1":
+ version "29.5.1"
+ resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.1.tgz#83c818aa9a87da27d6da85d3378e5a34d2f31a47"
+ integrity sha512-tEuVcHrpaixS36w7hpsfLBLpjtMRJUE09/MHXn923LOVojDwyC14cWcfc0rDs0VEfUyYmt/+iX1kxxp+gZMcaQ==
+ dependencies:
+ expect "^29.0.0"
+ pretty-format "^29.0.0"
+
"@types/node@*":
version "20.1.3"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.1.3.tgz#bc8e7cd8065a5fc355a3a191a68db8019c58bc00"
@@ -2152,7 +2167,7 @@ argparse@^2.0.1:
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
-asap@~2.0.3, asap@~2.0.6:
+asap@~2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==
@@ -2665,13 +2680,6 @@ cosmiconfig@^5.0.5, cosmiconfig@^5.1.0:
js-yaml "^3.13.1"
parse-json "^4.0.0"
-cross-fetch@^3.1.5:
- version "3.1.5"
- resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f"
- integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==
- dependencies:
- node-fetch "2.6.7"
-
cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
@@ -2795,6 +2803,11 @@ diff-sequences@^29.4.3:
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2"
integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==
+diff-sequences@^29.6.3:
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921"
+ integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==
+
doctrine@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
@@ -3041,6 +3054,17 @@ exit@^0.1.2:
resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==
+expect@^29.0.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc"
+ integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==
+ dependencies:
+ "@jest/expect-utils" "^29.7.0"
+ jest-get-type "^29.6.3"
+ jest-matcher-utils "^29.7.0"
+ jest-message-util "^29.7.0"
+ jest-util "^29.7.0"
+
expect@^29.5.0:
version "29.5.0"
resolved "https://registry.yarnpkg.com/expect/-/expect-29.5.0.tgz#68c0509156cb2a0adb8865d413b137eeaae682f7"
@@ -3088,24 +3112,6 @@ fb-watchman@^2.0.0:
dependencies:
bser "2.1.1"
-fbjs-css-vars@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8"
- integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==
-
-fbjs@^3.0.0:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.4.tgz#e1871c6bd3083bac71ff2da868ad5067d37716c6"
- integrity sha512-ucV0tDODnGV3JCnnkmoszb5lf4bNpzjv80K41wd4k798Etq+UYD0y0TIfalLjZoKgjive6/adkRnszwapiDgBQ==
- dependencies:
- cross-fetch "^3.1.5"
- fbjs-css-vars "^1.0.0"
- loose-envify "^1.0.0"
- object-assign "^4.1.0"
- promise "^7.1.1"
- setimmediate "^1.0.5"
- ua-parser-js "^0.7.30"
-
file-entry-cache@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
@@ -3659,6 +3665,16 @@ jest-diff@^29.5.0:
jest-get-type "^29.4.3"
pretty-format "^29.5.0"
+jest-diff@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a"
+ integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==
+ dependencies:
+ chalk "^4.0.0"
+ diff-sequences "^29.6.3"
+ jest-get-type "^29.6.3"
+ pretty-format "^29.7.0"
+
jest-docblock@^29.4.3:
version "29.4.3"
resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.4.3.tgz#90505aa89514a1c7dceeac1123df79e414636ea8"
@@ -3736,6 +3752,16 @@ jest-matcher-utils@^29.5.0:
jest-get-type "^29.4.3"
pretty-format "^29.5.0"
+jest-matcher-utils@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12"
+ integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==
+ dependencies:
+ chalk "^4.0.0"
+ jest-diff "^29.7.0"
+ jest-get-type "^29.6.3"
+ pretty-format "^29.7.0"
+
jest-message-util@^29.5.0:
version "29.5.0"
resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.5.0.tgz#1f776cac3aca332ab8dd2e3b41625435085c900e"
@@ -3751,6 +3777,21 @@ jest-message-util@^29.5.0:
slash "^3.0.0"
stack-utils "^2.0.3"
+jest-message-util@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3"
+ integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==
+ dependencies:
+ "@babel/code-frame" "^7.12.13"
+ "@jest/types" "^29.6.3"
+ "@types/stack-utils" "^2.0.0"
+ chalk "^4.0.0"
+ graceful-fs "^4.2.9"
+ micromatch "^4.0.4"
+ pretty-format "^29.7.0"
+ slash "^3.0.0"
+ stack-utils "^2.0.3"
+
jest-mock@^29.5.0:
version "29.5.0"
resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.5.0.tgz#26e2172bcc71d8b0195081ff1f146ac7e1518aed"
@@ -3906,6 +3947,18 @@ jest-util@^29.5.0:
graceful-fs "^4.2.9"
picomatch "^2.2.3"
+jest-util@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc"
+ integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==
+ dependencies:
+ "@jest/types" "^29.6.3"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ ci-info "^3.2.0"
+ graceful-fs "^4.2.9"
+ picomatch "^2.2.3"
+
jest-validate@^29.2.1:
version "29.7.0"
resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c"
@@ -4156,6 +4209,11 @@ lodash.throttle@^4.1.1:
resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
integrity sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==
+lodash@^4.17.21:
+ version "4.17.21"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+ integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
+
log-symbols@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503"
@@ -4647,13 +4705,6 @@ node-dir@^0.1.17:
dependencies:
minimatch "^3.0.2"
-node-fetch@2.6.7:
- version "2.6.7"
- resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
- integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
- dependencies:
- whatwg-url "^5.0.0"
-
node-fetch@^2.2.0, node-fetch@^2.6.0:
version "2.6.11"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.11.tgz#cde7fc71deef3131ef80a738919f999e6edfff25"
@@ -4705,7 +4756,7 @@ ob1@0.76.8:
resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.76.8.tgz#ac4c459465b1c0e2c29aaa527e09fc463d3ffec8"
integrity sha512-dlBkJJV5M/msj9KYA9upc+nUWVwuOFFTbu28X6kZeGwcuW+JxaHSBZ70SYQnk5M+j5JbNLR6yKHmgW4M5E7X5g==
-object-assign@^4.1.0, object-assign@^4.1.1:
+object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
@@ -4933,6 +4984,15 @@ pretty-format@^26.5.2, pretty-format@^26.6.2:
ansi-styles "^4.0.0"
react-is "^17.0.1"
+pretty-format@^29.0.0, pretty-format@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812"
+ integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==
+ dependencies:
+ "@jest/schemas" "^29.6.3"
+ ansi-styles "^5.0.0"
+ react-is "^18.0.0"
+
pretty-format@^29.5.0:
version "29.5.0"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.5.0.tgz#283134e74f70e2e3e7229336de0e4fce94ccde5a"
@@ -4942,27 +5002,11 @@ pretty-format@^29.5.0:
ansi-styles "^5.0.0"
react-is "^18.0.0"
-pretty-format@^29.7.0:
- version "29.7.0"
- resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812"
- integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==
- dependencies:
- "@jest/schemas" "^29.6.3"
- ansi-styles "^5.0.0"
- react-is "^18.0.0"
-
process-nextick-args@~2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
-promise@^7.1.1:
- version "7.3.1"
- resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
- integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==
- dependencies:
- asap "~2.0.3"
-
promise@^8.3.0:
version "8.3.0"
resolved "https://registry.yarnpkg.com/promise/-/promise-8.3.0.tgz#8cb333d1edeb61ef23869fbb8a4ea0279ab60e0a"
@@ -5057,15 +5101,15 @@ react-native-animated-pagination-dots@^0.1.73:
resolved "https://registry.yarnpkg.com/react-native-animated-pagination-dots/-/react-native-animated-pagination-dots-0.1.73.tgz#b559bf2faea50b848ff9234a557561ad15298118"
integrity sha512-yg6RL0ph3UN+KHX5NDa1iPVxh0J6h9dIn4zoColhJeAGV9TTl8SlaucwcBWaLd7DeUoJgkPxB/O4zJMAcpI/FQ==
-react-native-gesture-handler@^1.9.0:
- version "1.10.3"
- resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-1.10.3.tgz#942bbf2963bbf49fa79593600ee9d7b5dab3cfc0"
- integrity sha512-cBGMi1IEsIVMgoox4RvMx7V2r6bNKw0uR1Mu1o7NbuHS6BRSVLq0dP34l2ecnPlC+jpWd3le6Yg1nrdCjby2Mw==
+react-native-gesture-handler@2.13.4:
+ version "2.13.4"
+ resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-2.13.4.tgz#6a99384330278c4488bcfc7f1814be3e0d7401fd"
+ integrity sha512-smpYOVbvWABpq2H+lmDnfOLCTH934aUPO1w2/pQXvm1j+M/vmGQmvgRDJOpXcks17HLtNNKXD6tcODf3aPqDfA==
dependencies:
"@egjs/hammerjs" "^2.0.17"
- fbjs "^3.0.0"
hoist-non-react-statics "^3.3.0"
invariant "^2.2.4"
+ lodash "^4.17.21"
prop-types "^15.7.2"
react-native-reanimated@3.5.4:
@@ -5078,15 +5122,15 @@ react-native-reanimated@3.5.4:
convert-source-map "^2.0.0"
invariant "^2.2.4"
-react-native-safe-area-context@^3.1.9:
- version "3.4.1"
- resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-3.4.1.tgz#c967a52903d55fe010b2428e5368b42f1debc0a7"
- integrity sha512-xfpVd0CiZR7oBhuwJ2HcZMehg5bjha1Ohu1XHpcT+9ykula0TgovH2BNU0R5Krzf/jBR1LMjR6VabxdlUjqxcA==
+react-native-safe-area-context@^4.4.1:
+ version "4.7.4"
+ resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-4.7.4.tgz#3dd8438971e70043d76f2428ede75b8a9639265e"
+ integrity sha512-3LR3DCq9pdzlbq6vsHGWBFehXAKDh2Ljug6jWhLWs1QFuJHM6AS2+mH2JfKlB2LqiSFZOBcZfHQFz0sGaA3uqg==
-react-native-screens@~3.20.0:
- version "3.20.0"
- resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-3.20.0.tgz#4d154177395e5541387d9a05bc2e12e54d2fb5b1"
- integrity sha512-joWUKWAVHxymP3mL9gYApFHAsbd9L6ZcmpoZa6Sl3W/82bvvNVMqcfP7MeNqVCg73qZ8yL4fW+J/syusHleUgg==
+react-native-screens@3.27.0:
+ version "3.27.0"
+ resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-3.27.0.tgz#2ac39f78dee27df97d3b6fb11ebf8e5751aa986a"
+ integrity sha512-FzSUygZ7yLQyhDJZsl7wU68LwRpVtVdqOPWribmEU3Tf26FohFGGcfJx1D8lf2V2Teb8tI+IaLnXCKbyh2xffA==
dependencies:
react-freeze "^1.0.0"
warn-once "^0.1.0"
@@ -5422,11 +5466,6 @@ set-blocking@^2.0.0:
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==
-setimmediate@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
- integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==
-
setprototypeof@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
@@ -5761,11 +5800,6 @@ type-fest@^0.7.1:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48"
integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==
-ua-parser-js@^0.7.30:
- version "0.7.35"
- resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.35.tgz#8bda4827be4f0b1dda91699a29499575a1f1d307"
- integrity sha512-veRf7dawaj9xaWEu9HoTVn5Pggtc/qj+kqTOFvNiN1l0YdxwC1kvel57UCjThjGa3BHBihE8/UJAHI+uQHmd/g==
-
uglify-es@^3.1.9:
version "3.3.9"
resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677"
diff --git a/ios/Fabric/RNCPagerViewComponentView.mm b/ios/Fabric/RNCPagerViewComponentView.mm
index eac28637..37bf07cc 100644
--- a/ios/Fabric/RNCPagerViewComponentView.mm
+++ b/ios/Fabric/RNCPagerViewComponentView.mm
@@ -2,7 +2,6 @@
#import
#import "RNCPagerViewComponentView.h"
-#import "RNCPagerScrollView.h"
#import
#import
#import
@@ -21,9 +20,9 @@ @interface RNCPagerViewComponentView ()
+#import
+#import
+#import "UIViewController+CreateExtension.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface LEGACY_RNCPagerViewComponentView : RCTViewComponentView
+
+@property(strong, nonatomic, readonly) UIPageViewController *nativePageViewController;
+@property(nonatomic, strong) NSMutableArray *nativeChildrenViewControllers;
+@property(nonatomic) NSInteger initialPage;
+@property(nonatomic) NSInteger currentIndex;
+@property(nonatomic) NSInteger destinationIndex;
+@property(nonatomic) NSString* layoutDirection;
+@property(nonatomic) BOOL overdrag;
+
+- (void)setPage:(NSInteger)number;
+- (void)setPageWithoutAnimation:(NSInteger)number;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif
diff --git a/ios/LEGACY/Fabric/LEGACY_RNCPagerViewComponentView.mm b/ios/LEGACY/Fabric/LEGACY_RNCPagerViewComponentView.mm
new file mode 100644
index 00000000..677c55e0
--- /dev/null
+++ b/ios/LEGACY/Fabric/LEGACY_RNCPagerViewComponentView.mm
@@ -0,0 +1,403 @@
+#ifdef RCT_NEW_ARCH_ENABLED
+
+#import
+#import "LEGACY_RNCPagerViewComponentView.h"
+#import
+#import
+#import
+#import
+
+#import "RCTFabricComponentsPlugins.h"
+#import "React/RCTConversions.h"
+
+#import
+#import "RCTOnPageScrollEvent.h"
+
+using namespace facebook::react;
+
+@interface LEGACY_RNCPagerViewComponentView ()
+@end
+
+@implementation LEGACY_RNCPagerViewComponentView {
+ LayoutMetrics _layoutMetrics;
+ UIScrollView *scrollView;
+}
+
+- (void)initializeNativePageViewController {
+ const auto &viewProps = *std::static_pointer_cast(_props);
+ NSDictionary *options = @{ UIPageViewControllerOptionInterPageSpacingKey: @(viewProps.pageMargin) };
+ UIPageViewControllerNavigationOrientation orientation = UIPageViewControllerNavigationOrientationHorizontal;
+ switch (viewProps.orientation) {
+ case LEGACY_RNCViewPagerOrientation::Horizontal:
+ orientation = UIPageViewControllerNavigationOrientationHorizontal;
+ break;
+ case LEGACY_RNCViewPagerOrientation::Vertical:
+ orientation = UIPageViewControllerNavigationOrientationVertical;
+ break;
+ }
+ _nativePageViewController = [[UIPageViewController alloc]
+ initWithTransitionStyle: UIPageViewControllerTransitionStyleScroll
+ navigationOrientation:orientation
+ options:options];
+ _nativePageViewController.dataSource = self;
+ _nativePageViewController.delegate = self;
+ _nativePageViewController.view.frame = self.frame;
+ self.contentView = _nativePageViewController.view;
+
+ for (UIView *subview in _nativePageViewController.view.subviews) {
+ if([subview isKindOfClass:UIScrollView.class]){
+ ((UIScrollView *)subview).delegate = self;
+ ((UIScrollView *)subview).delaysContentTouches = NO;
+ scrollView = (UIScrollView *)subview;
+ }
+ }
+}
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+ if (self = [super initWithFrame:frame]) {
+ static const auto defaultProps = std::make_shared();
+ _props = defaultProps;
+ _nativeChildrenViewControllers = [[NSMutableArray alloc] init];
+ _currentIndex = -1;
+ _destinationIndex = -1;
+ _layoutDirection = @"ltr";
+ _overdrag = NO;
+ }
+
+ return self;
+}
+
+- (void)willMoveToSuperview:(UIView *)newSuperview {
+ if (newSuperview != nil) {
+ [self initializeNativePageViewController];
+ [self goTo:_currentIndex animated:NO];
+ }
+}
+
+#pragma mark - React API
+
+- (void)mountChildComponentView:(UIView *)childComponentView index:(NSInteger)index {
+ UIViewController *wrapper = [[UIViewController alloc] initWithView:childComponentView];
+ [_nativeChildrenViewControllers insertObject:wrapper atIndex:index];
+}
+
+- (void)unmountChildComponentView:(UIView *)childComponentView index:(NSInteger)index {
+ [[_nativeChildrenViewControllers objectAtIndex:index].view removeFromSuperview];
+ [_nativeChildrenViewControllers objectAtIndex:index].view = nil;
+ [_nativeChildrenViewControllers removeObjectAtIndex:index];
+
+ NSInteger maxPage = _nativeChildrenViewControllers.count - 1;
+
+ if (self.currentIndex >= maxPage) {
+ [self goTo:maxPage animated:NO];
+ }
+}
+
+
+-(void)updateLayoutMetrics:(const facebook::react::LayoutMetrics &)layoutMetrics oldLayoutMetrics:(const facebook::react::LayoutMetrics &)oldLayoutMetrics {
+ [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:_layoutMetrics];
+ self.contentView.frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame());
+ _layoutMetrics = layoutMetrics;
+}
+
+
+-(void)prepareForRecycle {
+ [super prepareForRecycle];
+
+ _nativeChildrenViewControllers = [[NSMutableArray alloc] init];
+ [_nativePageViewController.view removeFromSuperview];
+ _nativePageViewController = nil;
+
+ _currentIndex = -1;
+}
+
+- (void)shouldDismissKeyboard:(LEGACY_RNCViewPagerKeyboardDismissMode)dismissKeyboard {
+ UIScrollViewKeyboardDismissMode dismissKeyboardMode = UIScrollViewKeyboardDismissModeNone;
+ switch (dismissKeyboard) {
+ case LEGACY_RNCViewPagerKeyboardDismissMode::None:
+ dismissKeyboardMode = UIScrollViewKeyboardDismissModeNone;
+ break;
+ case LEGACY_RNCViewPagerKeyboardDismissMode::OnDrag:
+ dismissKeyboardMode = UIScrollViewKeyboardDismissModeOnDrag;
+ break;
+ }
+ scrollView.keyboardDismissMode = dismissKeyboardMode;
+}
+
+
+- (void)updateProps:(const facebook::react::Props::Shared &)props oldProps:(const facebook::react::Props::Shared &)oldProps{
+ const auto &oldScreenProps = *std::static_pointer_cast(_props);
+ const auto &newScreenProps = *std::static_pointer_cast(props);
+
+ // change index only once
+ if (_currentIndex == -1) {
+ _currentIndex = newScreenProps.initialPage;
+ [self shouldDismissKeyboard: newScreenProps.keyboardDismissMode];
+ }
+
+ const auto newLayoutDirectionStr = RCTNSStringFromString(toString(newScreenProps.layoutDirection));
+
+
+ if (self.layoutDirection != newLayoutDirectionStr) {
+ self.layoutDirection = newLayoutDirectionStr;
+ }
+
+ if (oldScreenProps.keyboardDismissMode != newScreenProps.keyboardDismissMode) {
+ [self shouldDismissKeyboard: newScreenProps.keyboardDismissMode];
+ }
+
+ if (newScreenProps.scrollEnabled != scrollView.scrollEnabled) {
+ scrollView.scrollEnabled = newScreenProps.scrollEnabled;
+ }
+
+ if (newScreenProps.overdrag != _overdrag) {
+ _overdrag = newScreenProps.overdrag;
+ }
+
+ [super updateProps:props oldProps:oldProps];
+}
+
+- (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args {
+ RCTLEGACY_RNCViewPagerHandleCommand(self, commandName, args);
+}
+
+#pragma mark - Internal methods
+
+- (void)setPage:(NSInteger)index {
+ [self goTo:index animated:YES];
+}
+
+- (void)setPageWithoutAnimation:(NSInteger)index {
+ [self goTo:index animated:NO];
+}
+
+- (void)disableSwipe {
+ self.nativePageViewController.view.userInteractionEnabled = NO;
+}
+
+- (void)enableSwipe {
+ self.nativePageViewController.view.userInteractionEnabled = YES;
+}
+
+- (void)goTo:(NSInteger)index animated:(BOOL)animated {
+ NSInteger numberOfPages = _nativeChildrenViewControllers.count;
+
+ [self disableSwipe];
+
+ _destinationIndex = index;
+
+
+ if (numberOfPages == 0 || index < 0 || index > numberOfPages - 1) {
+ return;
+ }
+
+ BOOL isForward = (index > self.currentIndex && [self isLtrLayout]) || (index < self.currentIndex && ![self isLtrLayout]);
+ UIPageViewControllerNavigationDirection direction = isForward ? UIPageViewControllerNavigationDirectionForward : UIPageViewControllerNavigationDirectionReverse;
+
+ long diff = labs(index - _currentIndex);
+
+ [self setPagerViewControllers:index
+ direction:direction
+ animated:diff == 0 ? NO : animated];
+
+}
+
+- (void)setPagerViewControllers:(NSInteger)index
+ direction:(UIPageViewControllerNavigationDirection)direction
+ animated:(BOOL)animated{
+ if (_nativePageViewController == nil) {
+ [self enableSwipe];
+ return;
+ }
+
+ __weak LEGACY_RNCPagerViewComponentView *weakSelf = self;
+ [_nativePageViewController setViewControllers:@[[_nativeChildrenViewControllers objectAtIndex:index]]
+ direction:direction
+ animated:animated
+ completion:^(BOOL finished) {
+ __strong LEGACY_RNCPagerViewComponentView *strongSelf = weakSelf;
+ [strongSelf enableSwipe];
+ if (strongSelf->_eventEmitter != nullptr ) {
+ const auto strongEventEmitter = *std::dynamic_pointer_cast(strongSelf->_eventEmitter);
+ int position = (int) index;
+ strongEventEmitter.onPageSelected(LEGACY_RNCViewPagerEventEmitter::OnPageSelected{.position = static_cast(position)});
+ strongSelf->_currentIndex = index;
+ }
+ }];
+}
+
+
+- (UIViewController *)nextControllerForController:(UIViewController *)controller
+ inDirection:(UIPageViewControllerNavigationDirection)direction {
+ NSUInteger numberOfPages = _nativeChildrenViewControllers.count;
+ NSInteger index = [_nativeChildrenViewControllers indexOfObject:controller];
+
+ if (index == NSNotFound) {
+ return nil;
+ }
+
+ direction == UIPageViewControllerNavigationDirectionForward ? index++ : index--;
+
+ if (index < 0 || (index > (numberOfPages - 1))) {
+ return nil;
+ }
+
+ return [_nativeChildrenViewControllers objectAtIndex:index];
+}
+
+- (UIViewController *)currentlyDisplayed {
+ return _nativePageViewController.viewControllers.firstObject;
+}
+
+#pragma mark - UIScrollViewDelegate
+
+- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
+ const auto strongEventEmitter = *std::dynamic_pointer_cast(_eventEmitter);
+ strongEventEmitter.onPageScrollStateChanged(LEGACY_RNCViewPagerEventEmitter::OnPageScrollStateChanged{.pageScrollState = LEGACY_RNCViewPagerEventEmitter::OnPageScrollStateChangedPageScrollState::Dragging });
+}
+
+- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
+
+ if (!_overdrag) {
+ NSInteger maxIndex = _nativeChildrenViewControllers.count - 1;
+ BOOL isFirstPage = [self isLtrLayout] ? _currentIndex == 0 : _currentIndex == maxIndex;
+ BOOL isLastPage = [self isLtrLayout] ? _currentIndex == maxIndex : _currentIndex == 0;
+ CGFloat contentOffset = [self isHorizontal] ? scrollView.contentOffset.x : scrollView.contentOffset.y;
+ CGFloat topBound = [self isHorizontal] ? scrollView.bounds.size.width : scrollView.bounds.size.height;
+
+ if ((isFirstPage && contentOffset <= topBound) || (isLastPage && contentOffset >= topBound)) {
+ CGPoint croppedOffset = [self isHorizontal] ? CGPointMake(topBound, 0) : CGPointMake(0, topBound);
+ *targetContentOffset = croppedOffset;
+ }
+ }
+
+ const auto strongEventEmitter = *std::dynamic_pointer_cast(_eventEmitter);
+ strongEventEmitter.onPageScrollStateChanged(LEGACY_RNCViewPagerEventEmitter::OnPageScrollStateChanged{.pageScrollState = LEGACY_RNCViewPagerEventEmitter::OnPageScrollStateChangedPageScrollState::Settling });
+}
+
+- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
+ const auto strongEventEmitter = *std::dynamic_pointer_cast(_eventEmitter);
+ strongEventEmitter.onPageScrollStateChanged(LEGACY_RNCViewPagerEventEmitter::OnPageScrollStateChanged{.pageScrollState = LEGACY_RNCViewPagerEventEmitter::OnPageScrollStateChangedPageScrollState::Idle });
+}
+
+- (BOOL)isHorizontal {
+ return _nativePageViewController.navigationOrientation == UIPageViewControllerNavigationOrientationHorizontal;
+}
+
+- (BOOL)isLtrLayout {
+ return [_layoutDirection isEqualToString: @"ltr"];
+}
+
+- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
+ CGPoint point = scrollView.contentOffset;
+
+ float offset = 0;
+
+ if (self.isHorizontal) {
+ if (scrollView.frame.size.width != 0) {
+ offset = (point.x - scrollView.frame.size.width)/scrollView.frame.size.width;
+ }
+ } else {
+ if (scrollView.frame.size.height != 0) {
+ offset = (point.y - scrollView.frame.size.height)/scrollView.frame.size.height;
+ }
+ }
+
+ float absoluteOffset = fabs(offset);
+
+ NSInteger position = self.currentIndex;
+
+ BOOL isAnimatingBackwards = offset<0;
+
+ if (scrollView.isDragging) {
+ _destinationIndex = isAnimatingBackwards ? _currentIndex - 1 : _currentIndex + 1;
+ }
+
+ if (isAnimatingBackwards) {
+ position = _destinationIndex;
+ absoluteOffset = fmax(0, 1 - absoluteOffset);
+ }
+
+ if (!_overdrag) {
+ NSInteger maxIndex = _nativeChildrenViewControllers.count - 1;
+ NSInteger firstPageIndex = [self isLtrLayout] ? 0 : maxIndex;
+ NSInteger lastPageIndex = [self isLtrLayout] ? maxIndex : 0;
+ BOOL isFirstPage = _currentIndex == firstPageIndex;
+ BOOL isLastPage = _currentIndex == lastPageIndex;
+ CGFloat contentOffset =[self isHorizontal] ? scrollView.contentOffset.x : scrollView.contentOffset.y;
+ CGFloat topBound = [self isHorizontal] ? scrollView.bounds.size.width : scrollView.bounds.size.height;
+
+ if ((isFirstPage && contentOffset <= topBound) || (isLastPage && contentOffset >= topBound)) {
+ CGPoint croppedOffset = [self isHorizontal] ? CGPointMake(topBound, 0) : CGPointMake(0, topBound);
+ scrollView.contentOffset = croppedOffset;
+ absoluteOffset=0;
+ position = isLastPage ? lastPageIndex : firstPageIndex;
+ }
+ }
+
+ float interpolatedOffset = absoluteOffset * labs(_destinationIndex - _currentIndex);
+
+ const auto strongEventEmitter = *std::dynamic_pointer_cast(_eventEmitter);
+ int eventPosition = (int) position;
+ strongEventEmitter.onPageScroll(LEGACY_RNCViewPagerEventEmitter::OnPageScroll{.position = static_cast(eventPosition), .offset = interpolatedOffset});
+
+ //This is temporary workaround to allow animations based on onPageScroll event
+ //until Fabric implements proper NativeAnimationDriver
+ RCTBridge *bridge = [RCTBridge currentBridge];
+
+ if (bridge) {
+ [bridge.eventDispatcher sendEvent:[[RCTOnPageScrollEvent alloc] initWithReactTag:[NSNumber numberWithInt:self.tag] position:@(position) offset:@(interpolatedOffset)]];
+ }
+
+}
+
+
+#pragma mark - UIPageViewControllerDelegate
+
+- (void)pageViewController:(UIPageViewController *)pageViewController
+ didFinishAnimating:(BOOL)finished
+ previousViewControllers:(nonnull NSArray *)previousViewControllers
+ transitionCompleted:(BOOL)completed {
+ if (completed) {
+ UIViewController* currentVC = [self currentlyDisplayed];
+ NSUInteger currentIndex = [_nativeChildrenViewControllers indexOfObject:currentVC];
+ _currentIndex = currentIndex;
+ int position = (int) currentIndex;
+ const auto strongEventEmitter = *std::dynamic_pointer_cast(_eventEmitter);
+ strongEventEmitter.onPageSelected(LEGACY_RNCViewPagerEventEmitter::OnPageSelected{.position = static_cast(position)});
+ strongEventEmitter.onPageScroll(LEGACY_RNCViewPagerEventEmitter::OnPageScroll{.position = static_cast(position), .offset = 0.0});
+ }
+}
+
+#pragma mark - UIPageViewControllerDataSource
+
+- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
+ viewControllerAfterViewController:(UIViewController *)viewController {
+
+ UIPageViewControllerNavigationDirection direction = [self isLtrLayout] ? UIPageViewControllerNavigationDirectionForward : UIPageViewControllerNavigationDirectionReverse;
+ return [self nextControllerForController:viewController inDirection:direction];
+}
+
+- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
+ viewControllerBeforeViewController:(UIViewController *)viewController {
+ UIPageViewControllerNavigationDirection direction = [self isLtrLayout] ? UIPageViewControllerNavigationDirectionReverse : UIPageViewControllerNavigationDirectionForward;
+ return [self nextControllerForController:viewController inDirection:direction];
+}
+
+#pragma mark - RCTComponentViewProtocol
+
++ (ComponentDescriptorProvider)componentDescriptorProvider
+{
+ return concreteComponentDescriptorProvider();
+}
+
+
+@end
+
+Class LEGACY_RNCViewPagerCls(void)
+{
+ return LEGACY_RNCPagerViewComponentView.class;
+}
+
+#endif
diff --git a/ios/LEGACY/LEGACY_RNCPagerView.h b/ios/LEGACY/LEGACY_RNCPagerView.h
new file mode 100644
index 00000000..b8a7a86b
--- /dev/null
+++ b/ios/LEGACY/LEGACY_RNCPagerView.h
@@ -0,0 +1,33 @@
+#import
+#import
+#import
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface LEGACY_RNCPagerView: UIView
+
+- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher;
+
+@property(nonatomic) NSInteger initialPage;
+@property(nonatomic) NSInteger lastReportedIndex;
+@property(nonatomic) NSInteger destinationIndex;
+@property(nonatomic) NSInteger currentIndex;
+@property(nonatomic) NSInteger pageMargin;
+@property(nonatomic, readonly) BOOL scrollEnabled;
+@property(nonatomic, readonly) UIScrollViewKeyboardDismissMode dismissKeyboard;
+@property(nonatomic) UIPageViewControllerNavigationOrientation orientation;
+@property(nonatomic, copy) RCTDirectEventBlock onPageSelected;
+@property(nonatomic, copy) RCTDirectEventBlock onPageScroll;
+@property(nonatomic, copy) RCTDirectEventBlock onPageScrollStateChanged;
+@property(nonatomic) BOOL overdrag;
+@property(nonatomic) NSString* layoutDirection;
+@property(nonatomic, assign) BOOL animating;
+
+- (void)goTo:(NSInteger)index animated:(BOOL)animated;
+- (void)shouldScroll:(BOOL)scrollEnabled;
+- (void)shouldDismissKeyboard:(NSString *)dismissKeyboard;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/ios/LEGACY/LEGACY_RNCPagerView.m b/ios/LEGACY/LEGACY_RNCPagerView.m
new file mode 100644
index 00000000..add548c8
--- /dev/null
+++ b/ios/LEGACY/LEGACY_RNCPagerView.m
@@ -0,0 +1,464 @@
+
+#import "LEGACY_RNCPagerView.h"
+#import "React/RCTLog.h"
+#import
+
+#import "UIViewController+CreateExtension.h"
+#import "RCTOnPageScrollEvent.h"
+#import "RCTOnPageScrollStateChanged.h"
+#import "RCTOnPageSelected.h"
+#import
+
+@interface LEGACY_RNCPagerView ()
+
+@property(nonatomic, strong) UIPageViewController *reactPageViewController;
+@property(nonatomic, strong) RCTEventDispatcher *eventDispatcher;
+
+@property(nonatomic, weak) UIScrollView *scrollView;
+@property(nonatomic, weak) UIView *currentView;
+
+@property(nonatomic, strong) NSHashTable *cachedControllers;
+@property(nonatomic, assign) CGPoint lastContentOffset;
+
+- (void)goTo:(NSInteger)index animated:(BOOL)animated;
+- (void)shouldScroll:(BOOL)scrollEnabled;
+- (void)shouldDismissKeyboard:(NSString *)dismissKeyboard;
+
+
+@end
+
+@implementation LEGACY_RNCPagerView {
+ uint16_t _coalescingKey;
+}
+
+- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher {
+ if (self = [super init]) {
+ _scrollEnabled = YES;
+ _pageMargin = 0;
+ _lastReportedIndex = -1;
+ _destinationIndex = -1;
+ _orientation = UIPageViewControllerNavigationOrientationHorizontal;
+ _currentIndex = 0;
+ _dismissKeyboard = UIScrollViewKeyboardDismissModeNone;
+ _coalescingKey = 0;
+ _eventDispatcher = eventDispatcher;
+ _cachedControllers = [NSHashTable hashTableWithOptions:NSHashTableStrongMemory];
+ _overdrag = NO;
+ _layoutDirection = @"ltr";
+ }
+ return self;
+}
+
+- (void)layoutSubviews {
+ [super layoutSubviews];
+ if (self.reactPageViewController) {
+ [self shouldScroll:self.scrollEnabled];
+ }
+}
+
+- (void)didUpdateReactSubviews {
+ if (!self.reactPageViewController && self.reactViewController != nil) {
+ [self embed];
+ [self setupInitialController];
+ } else {
+ [self updateDataSource];
+ }
+}
+
+- (void)didMoveToSuperview {
+ [super didMoveToSuperview];
+ if (!self.reactPageViewController && self.reactViewController != nil) {
+ [self embed];
+ [self setupInitialController];
+ }
+}
+
+- (void)didMoveToWindow {
+ [super didMoveToWindow];
+ if (!self.reactPageViewController && self.reactViewController != nil) {
+ [self embed];
+ [self setupInitialController];
+ }
+
+ if (self.reactViewController.navigationController != nil && self.reactViewController.navigationController.interactivePopGestureRecognizer != nil) {
+ [self.scrollView.panGestureRecognizer requireGestureRecognizerToFail:self.reactViewController.navigationController.interactivePopGestureRecognizer];
+ }
+}
+
+- (void)embed {
+ NSDictionary *options = @{ UIPageViewControllerOptionInterPageSpacingKey: @(self.pageMargin) };
+ UIPageViewController *pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll
+ navigationOrientation:self.orientation
+ options:options];
+ pageViewController.delegate = self;
+ pageViewController.dataSource = self;
+
+ for (UIView *subview in pageViewController.view.subviews) {
+ if([subview isKindOfClass:UIScrollView.class]){
+ ((UIScrollView *)subview).delegate = self;
+ ((UIScrollView *)subview).keyboardDismissMode = _dismissKeyboard;
+ ((UIScrollView *)subview).delaysContentTouches = YES;
+ self.scrollView = (UIScrollView *)subview;
+ }
+ }
+
+ self.reactPageViewController = pageViewController;
+
+ [self reactAddControllerToClosestParent:pageViewController];
+ [self addSubview:pageViewController.view];
+
+ pageViewController.view.frame = self.bounds;
+
+ [self shouldScroll:self.scrollEnabled];
+
+ [pageViewController.view layoutIfNeeded];
+}
+
+- (void)shouldScroll:(BOOL)scrollEnabled {
+ _scrollEnabled = scrollEnabled;
+ if (self.reactPageViewController.view) {
+ self.scrollView.scrollEnabled = scrollEnabled;
+ }
+}
+
+- (void)shouldDismissKeyboard:(NSString *)dismissKeyboard {
+ _dismissKeyboard = [dismissKeyboard isEqual: @"on-drag"] ?
+ UIScrollViewKeyboardDismissModeOnDrag : UIScrollViewKeyboardDismissModeNone;
+ self.scrollView.keyboardDismissMode = _dismissKeyboard;
+}
+
+- (void)setupInitialController {
+ UIView *initialView = self.reactSubviews[self.initialPage];
+ if (initialView) {
+ UIViewController *initialController = nil;
+ if (initialView.reactViewController) {
+ initialController = initialView.reactViewController;
+ } else {
+ initialController = [[UIViewController alloc] initWithView:initialView];
+ }
+
+ [self.cachedControllers addObject:initialController];
+
+ [self setReactViewControllers:self.initialPage
+ with:initialController
+ direction:UIPageViewControllerNavigationDirectionForward
+ animated:YES
+ shouldCallOnPageSelected:YES];
+ }
+}
+
+- (void)setReactViewControllers:(NSInteger)index
+ with:(UIViewController *)controller
+ direction:(UIPageViewControllerNavigationDirection)direction
+ animated:(BOOL)animated
+ shouldCallOnPageSelected:(BOOL)shouldCallOnPageSelected {
+ if (self.reactPageViewController == nil) {
+ [self enableSwipe];
+ return;
+ }
+
+ NSArray *currentVCs = self.reactPageViewController.viewControllers;
+ if (currentVCs.count == 1 && [currentVCs.firstObject isEqual:controller]) {
+ [self enableSwipe];
+ return;
+ }
+
+ __weak LEGACY_RNCPagerView *weakSelf = self;
+ uint16_t coalescingKey = _coalescingKey++;
+
+ if (animated == YES) {
+ self.animating = YES;
+ }
+
+ [self.reactPageViewController setViewControllers:@[controller]
+ direction:direction
+ animated:animated
+ completion:^(BOOL finished) {
+ __strong typeof(self) strongSelf = weakSelf;
+ strongSelf.currentIndex = index;
+ strongSelf.currentView = controller.view;
+
+ [strongSelf enableSwipe];
+
+ if (finished) {
+ strongSelf.animating = NO;
+ }
+
+ if (strongSelf.eventDispatcher) {
+ if (strongSelf.lastReportedIndex != strongSelf.currentIndex) {
+ if (shouldCallOnPageSelected) {
+ [strongSelf.eventDispatcher sendEvent:[[RCTOnPageSelected alloc] initWithReactTag:strongSelf.reactTag position:@(index) coalescingKey:coalescingKey]];
+ }
+ strongSelf.lastReportedIndex = strongSelf.currentIndex;
+ }
+ }
+ }];
+}
+
+- (UIViewController *)currentlyDisplayed {
+ return self.reactPageViewController.viewControllers.firstObject;
+}
+
+- (UIViewController *)findCachedControllerForView:(UIView *)view {
+ for (UIViewController *controller in self.cachedControllers) {
+ if (controller.view.reactTag == view.reactTag) {
+ return controller;
+ }
+ }
+ return nil;
+}
+
+- (void)updateDataSource {
+ if (!self.currentView && self.reactSubviews.count == 0) {
+ return;
+ }
+
+ NSInteger newIndex = self.currentView ? [self.reactSubviews indexOfObject:self.currentView] : 0;
+
+ if (newIndex == NSNotFound) {
+ //Current view was removed
+ NSInteger maxPage = self.reactSubviews.count - 1;
+ NSInteger fallbackIndex = self.currentIndex >= maxPage ? maxPage : self.currentIndex;
+
+ [self goTo:fallbackIndex animated:NO];
+ } else {
+ [self goTo:newIndex animated:NO];
+ }
+}
+
+- (void)disableSwipe {
+ self.reactPageViewController.view.userInteractionEnabled = NO;
+}
+
+- (void)enableSwipe {
+ self.reactPageViewController.view.userInteractionEnabled = YES;
+}
+
+- (void)goTo:(NSInteger)index animated:(BOOL)animated {
+ NSInteger numberOfPages = self.reactSubviews.count;
+
+ [self disableSwipe];
+
+ _destinationIndex = index;
+
+ if (numberOfPages == 0 || index < 0 || index > numberOfPages - 1) {
+ return;
+ }
+
+ BOOL isRTL = ![self isLtrLayout];
+
+ BOOL isForward = (index > self.currentIndex && !isRTL) || (index < self.currentIndex && isRTL);
+
+
+ UIPageViewControllerNavigationDirection direction = isForward ? UIPageViewControllerNavigationDirectionForward : UIPageViewControllerNavigationDirectionReverse;
+
+ long diff = labs(index - _currentIndex);
+
+ [self goToViewController:index direction:direction animated:(!self.animating && animated) shouldCallOnPageSelected: YES];
+
+ if (diff == 0) {
+ [self goToViewController:index direction:direction animated:NO shouldCallOnPageSelected:YES];
+ }
+}
+
+- (void)goToViewController:(NSInteger)index
+ direction:(UIPageViewControllerNavigationDirection)direction
+ animated:(BOOL)animated
+ shouldCallOnPageSelected:(BOOL)shouldCallOnPageSelected {
+ UIView *viewToDisplay = self.reactSubviews[index];
+ UIViewController *controllerToDisplay = [self findAndCacheControllerForView:viewToDisplay];
+ [self setReactViewControllers:index
+ with:controllerToDisplay
+ direction:direction
+ animated:animated
+ shouldCallOnPageSelected:shouldCallOnPageSelected];
+}
+
+- (UIViewController *)findAndCacheControllerForView:(UIView *)viewToDisplay {
+ if (!viewToDisplay) { return nil; }
+
+ UIViewController *controllerToDisplay = [self findCachedControllerForView:viewToDisplay];
+ UIViewController *current = [self currentlyDisplayed];
+
+ if (!controllerToDisplay && current.view.reactTag == viewToDisplay.reactTag) {
+ controllerToDisplay = current;
+ }
+ if (!controllerToDisplay) {
+ if (viewToDisplay.reactViewController) {
+ controllerToDisplay = viewToDisplay.reactViewController;
+ } else {
+ controllerToDisplay = [[UIViewController alloc] initWithView:viewToDisplay];
+ }
+ }
+ [self.cachedControllers addObject:controllerToDisplay];
+
+ return controllerToDisplay;
+}
+
+- (UIViewController *)nextControllerForController:(UIViewController *)controller
+ inDirection:(UIPageViewControllerNavigationDirection)direction {
+ NSUInteger numberOfPages = self.reactSubviews.count;
+ NSInteger index = [self.reactSubviews indexOfObject:controller.view];
+
+ if (index == NSNotFound) {
+ return nil;
+ }
+
+ direction == UIPageViewControllerNavigationDirectionForward ? index++ : index--;
+
+ if (index < 0 || (index > (numberOfPages - 1))) {
+ return nil;
+ }
+
+ UIView *viewToDisplay = self.reactSubviews[index];
+
+ return [self findAndCacheControllerForView:viewToDisplay];
+}
+
+#pragma mark - UIPageViewControllerDelegate
+
+- (void)pageViewController:(UIPageViewController *)pageViewController
+ didFinishAnimating:(BOOL)finished
+ previousViewControllers:(nonnull NSArray *)previousViewControllers
+ transitionCompleted:(BOOL)completed {
+
+ if (completed) {
+ UIViewController* currentVC = [self currentlyDisplayed];
+ NSUInteger currentIndex = [self.reactSubviews indexOfObject:currentVC.view];
+
+ self.currentIndex = currentIndex;
+ self.currentView = currentVC.view;
+ [self.eventDispatcher sendEvent:[[RCTOnPageSelected alloc] initWithReactTag:self.reactTag position:@(currentIndex) coalescingKey:_coalescingKey++]];
+ [self.eventDispatcher sendEvent:[[RCTOnPageScrollEvent alloc] initWithReactTag:self.reactTag position:@(currentIndex) offset:@(0.0)]];
+ self.lastReportedIndex = currentIndex;
+ }
+}
+
+#pragma mark - UIPageViewControllerDataSource
+
+- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
+ viewControllerAfterViewController:(UIViewController *)viewController {
+ UIPageViewControllerNavigationDirection direction = [self isLtrLayout] ? UIPageViewControllerNavigationDirectionForward : UIPageViewControllerNavigationDirectionReverse;
+ return [self nextControllerForController:viewController inDirection:direction];
+}
+
+- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
+ viewControllerBeforeViewController:(UIViewController *)viewController {
+ UIPageViewControllerNavigationDirection direction = [self isLtrLayout] ? UIPageViewControllerNavigationDirectionReverse : UIPageViewControllerNavigationDirectionForward;
+ return [self nextControllerForController:viewController inDirection:direction];
+}
+
+#pragma mark - UIPageControlDelegate
+
+- (void)pageControlValueChanged:(UIPageControl *)sender {
+ if (sender.currentPage != self.currentIndex) {
+ [self goTo:sender.currentPage animated:YES];
+ }
+}
+
+#pragma mark - UIScrollViewDelegate
+
+- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
+ [self.eventDispatcher sendEvent:[[RCTOnPageScrollStateChanged alloc] initWithReactTag:self.reactTag state:@"dragging" coalescingKey:_coalescingKey++]];
+}
+
+- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
+ [self.eventDispatcher sendEvent:[[RCTOnPageScrollStateChanged alloc] initWithReactTag:self.reactTag state:@"settling" coalescingKey:_coalescingKey++]];
+
+ if (!_overdrag) {
+ NSInteger maxIndex = self.reactSubviews.count - 1;
+ BOOL isFirstPage = [self isLtrLayout] ? _currentIndex == 0 : _currentIndex == maxIndex;
+ BOOL isLastPage = [self isLtrLayout] ? _currentIndex == maxIndex : _currentIndex == 0;
+ CGFloat contentOffset =[self isHorizontal] ? scrollView.contentOffset.x : scrollView.contentOffset.y;
+ CGFloat topBound = [self isHorizontal] ? scrollView.bounds.size.width : scrollView.bounds.size.height;
+
+ if ((isFirstPage && contentOffset <= topBound) || (isLastPage && contentOffset >= topBound)) {
+ CGPoint croppedOffset = [self isHorizontal] ? CGPointMake(topBound, 0) : CGPointMake(0, topBound);
+ *targetContentOffset = croppedOffset;
+ }
+ }
+}
+
+- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
+ [self.eventDispatcher sendEvent:[[RCTOnPageScrollStateChanged alloc] initWithReactTag:self.reactTag state:@"idle" coalescingKey:_coalescingKey++]];
+}
+
+- (BOOL)isHorizontal {
+ return self.orientation == UIPageViewControllerNavigationOrientationHorizontal;
+}
+
+- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
+ CGPoint point = scrollView.contentOffset;
+
+ float offset = 0;
+
+ if (self.isHorizontal) {
+ if (scrollView.frame.size.width != 0) {
+ offset = (point.x - scrollView.frame.size.width)/scrollView.frame.size.width;
+ }
+ } else {
+ if (scrollView.frame.size.height != 0) {
+ offset = (point.y - scrollView.frame.size.height)/scrollView.frame.size.height;
+ }
+ }
+
+ float absoluteOffset = fabs(offset);
+
+ NSInteger position = self.currentIndex;
+
+ BOOL isAnimatingBackwards = ([self isLtrLayout] && offset<0) || (![self isLtrLayout] && offset > 0.05f);
+
+ if (scrollView.isDragging) {
+ _destinationIndex = isAnimatingBackwards ? _currentIndex - 1 : _currentIndex + 1;
+ }
+
+ if(isAnimatingBackwards){
+ position = _destinationIndex;
+ absoluteOffset = fmax(0, 1 - absoluteOffset);
+ }
+
+ if (!_overdrag) {
+ NSInteger maxIndex = self.reactSubviews.count - 1;
+ NSInteger firstPageIndex = [self isLtrLayout] ? 0 : maxIndex;
+ NSInteger lastPageIndex = [self isLtrLayout] ? maxIndex : 0;
+ BOOL isFirstPage = _currentIndex == firstPageIndex;
+ BOOL isLastPage = _currentIndex == lastPageIndex;
+ CGFloat contentOffset =[self isHorizontal] ? scrollView.contentOffset.x : scrollView.contentOffset.y;
+ CGFloat topBound = [self isHorizontal] ? scrollView.bounds.size.width : scrollView.bounds.size.height;
+
+ if ((isFirstPage && contentOffset <= topBound) || (isLastPage && contentOffset >= topBound)) {
+ CGPoint croppedOffset = [self isHorizontal] ? CGPointMake(topBound, 0) : CGPointMake(0, topBound);
+ scrollView.contentOffset = croppedOffset;
+ absoluteOffset=0;
+ position = isLastPage ? lastPageIndex : firstPageIndex;
+ }
+ }
+
+ float interpolatedOffset = absoluteOffset * labs(_destinationIndex - _currentIndex);
+
+ self.lastContentOffset = scrollView.contentOffset;
+ [self.eventDispatcher sendEvent:[[RCTOnPageScrollEvent alloc] initWithReactTag:self.reactTag position:@(position) offset:@(interpolatedOffset)]];
+}
+
+- (NSString *)determineScrollDirection:(UIScrollView *)scrollView {
+ NSString *scrollDirection;
+ if (self.isHorizontal) {
+ if (self.lastContentOffset.x > scrollView.contentOffset.x) {
+ scrollDirection = @"left";
+ } else if (self.lastContentOffset.x < scrollView.contentOffset.x) {
+ scrollDirection = @"right";
+ }
+ } else {
+ if (self.lastContentOffset.y > scrollView.contentOffset.y) {
+ scrollDirection = @"up";
+ } else if (self.lastContentOffset.y < scrollView.contentOffset.y) {
+ scrollDirection = @"down";
+ }
+ }
+ return scrollDirection;
+}
+
+- (BOOL)isLtrLayout {
+ return [_layoutDirection isEqualToString:@"ltr"];
+}
+@end
diff --git a/ios/LEGACY/LEGACY_RNCPagerViewManager.h b/ios/LEGACY/LEGACY_RNCPagerViewManager.h
new file mode 100644
index 00000000..7225f921
--- /dev/null
+++ b/ios/LEGACY/LEGACY_RNCPagerViewManager.h
@@ -0,0 +1,13 @@
+
+#import
+#import
+#import
+#import
+#import "LEGACY_RNCPagerView.h"
+NS_ASSUME_NONNULL_BEGIN
+
+@interface LEGACY_RNCPagerViewManager : RCTViewManager
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/ios/LEGACY/LEGACY_RNCPagerViewManager.m b/ios/LEGACY/LEGACY_RNCPagerViewManager.m
new file mode 100644
index 00000000..c1776ae0
--- /dev/null
+++ b/ios/LEGACY/LEGACY_RNCPagerViewManager.m
@@ -0,0 +1,86 @@
+
+#import "LEGACY_RNCPagerViewManager.h"
+
+@implementation LEGACY_RNCPagerViewManager
+
+#pragma mark - RTC
+
+RCT_EXPORT_MODULE(LEGACY_RNCViewPager)
+
+RCT_EXPORT_VIEW_PROPERTY(initialPage, NSInteger)
+RCT_EXPORT_VIEW_PROPERTY(pageMargin, NSInteger)
+
+RCT_EXPORT_VIEW_PROPERTY(orientation, UIPageViewControllerNavigationOrientation)
+RCT_EXPORT_VIEW_PROPERTY(onPageSelected, RCTDirectEventBlock)
+RCT_EXPORT_VIEW_PROPERTY(onPageScroll, RCTDirectEventBlock)
+RCT_EXPORT_VIEW_PROPERTY(onPageScrollStateChanged, RCTDirectEventBlock)
+RCT_EXPORT_VIEW_PROPERTY(overdrag, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(layoutDirection, NSString)
+
+
+- (void) goToPage
+ : (nonnull NSNumber *)reactTag index
+ : (nonnull NSNumber *)index animated
+ : (BOOL)animated {
+ [self.bridge.uiManager addUIBlock:^(
+ RCTUIManager *uiManager,
+ NSDictionary *viewRegistry) {
+ LEGACY_RNCPagerView *view = (LEGACY_RNCPagerView *)viewRegistry[reactTag];
+ if (!view || ![view isKindOfClass:[LEGACY_RNCPagerView class]]) {
+ RCTLogError(@"Cannot find LEGACY_RNCPagerView with tag #%@", reactTag);
+ return;
+ }
+ if (!animated || !view.animating) {
+ [view goTo:index.integerValue animated:animated];
+ }
+ }];
+}
+
+- (void) changeScrollEnabled
+: (nonnull NSNumber *)reactTag enabled
+: (BOOL)enabled {
+ [self.bridge.uiManager addUIBlock:^(
+ RCTUIManager *uiManager,
+ NSDictionary *viewRegistry) {
+ LEGACY_RNCPagerView *view = (LEGACY_RNCPagerView *)viewRegistry[reactTag];
+ if (!view || ![view isKindOfClass:[LEGACY_RNCPagerView class]]) {
+ RCTLogError(@"Cannot find LEGACY_RNCPagerView with tag #%@", reactTag);
+ return;
+ }
+ [view shouldScroll:enabled];
+ }];
+}
+
+RCT_EXPORT_METHOD(setPage
+ : (nonnull NSNumber *)reactTag index
+ : (nonnull NSNumber *)index) {
+ [self goToPage:reactTag index:index animated:true];
+}
+
+RCT_EXPORT_METHOD(setPageWithoutAnimation
+ : (nonnull NSNumber *)reactTag index
+ : (nonnull NSNumber *)index) {
+ [self goToPage:reactTag index:index animated:false];
+}
+
+RCT_EXPORT_METHOD(setScrollEnabled
+ : (nonnull NSNumber *)reactTag enabled
+ : (nonnull NSNumber *)enabled) {
+ BOOL isEnabled = [enabled boolValue];
+ [self changeScrollEnabled:reactTag enabled:isEnabled];
+}
+
+RCT_CUSTOM_VIEW_PROPERTY(scrollEnabled, BOOL, LEGACY_RNCPagerView) {
+ [view shouldScroll:[RCTConvert BOOL:json]];
+}
+
+RCT_CUSTOM_VIEW_PROPERTY(keyboardDismissMode, NSString, LEGACY_RNCPagerView) {
+ [view shouldDismissKeyboard:[RCTConvert NSString:json]];
+}
+
+
+- (UIView *)view {
+ return [[LEGACY_RNCPagerView alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
+}
+
+@end
diff --git a/ios/RNCPagerScrollView.h b/ios/RNCPagerScrollView.h
index d060b6d3..d61de90b 100644
--- a/ios/RNCPagerScrollView.h
+++ b/ios/RNCPagerScrollView.h
@@ -1,2 +1,8 @@
+/*
+NOTE: This file is *not* currently used, for context see:
+- https://github.com/callstack/react-native-pager-view/pull/783#discussion_r1410295171
+- https://github.com/callstack/react-native-pager-view/pull/783#discussion_r1410316201
+*/
+
@interface RNCPagerScrollView : UIScrollView
@end
diff --git a/ios/RNCPagerScrollView.m b/ios/RNCPagerScrollView.m
index ffbffbfb..321befde 100644
--- a/ios/RNCPagerScrollView.m
+++ b/ios/RNCPagerScrollView.m
@@ -1,3 +1,8 @@
+/*
+NOTE: This file is *not* currently used, for context see:
+- https://github.com/callstack/react-native-pager-view/pull/783#discussion_r1410295171
+- https://github.com/callstack/react-native-pager-view/pull/783#discussion_r1410316201
+*/
#import "RNCPagerScrollView.h"
diff --git a/ios/RNCPagerView.m b/ios/RNCPagerView.m
index 69325a59..d0bb5c1d 100644
--- a/ios/RNCPagerView.m
+++ b/ios/RNCPagerView.m
@@ -5,7 +5,6 @@
#import "UIViewController+CreateExtension.h"
#import "RCTOnPageScrollEvent.h"
-#import "RNCPagerScrollView.h"
#import "RCTOnPageScrollStateChanged.h"
#import "React/RCTUIManagerObserverCoordinator.h"
#import "RCTOnPageSelected.h"
@@ -15,7 +14,7 @@ @interface RNCPagerView ()
@property(nonatomic, strong) id eventDispatcher;
-@property(nonatomic, strong) RNCPagerScrollView *scrollView;
+@property(nonatomic, strong) UIScrollView *scrollView;
@property(nonatomic, strong) UIView *containerView;
- (void)goTo:(NSInteger)index animated:(BOOL)animated;
@@ -40,13 +39,6 @@ - (instancetype)initWithEventDispatcher:(id)eventDis
return self;
}
-- (void)didMoveToWindow {
- // Disable scroll view pan gesture for navigation controller screen edge go back gesture
- if (self.reactViewController.navigationController != nil && self.reactViewController.navigationController.interactivePopGestureRecognizer != nil) {
- [self.scrollView.panGestureRecognizer requireGestureRecognizerToFail:self.reactViewController.navigationController.interactivePopGestureRecognizer];
- }
-}
-
- (void)didUpdateReactSubviews {
[self updateContentSizeIfNeeded];
}
@@ -71,7 +63,7 @@ - (void)removeReactSubview:(UIView *)subview {
}
- (void)embed {
- _scrollView = [[RNCPagerScrollView alloc] initWithFrame:self.bounds];
+ _scrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
_scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_scrollView.delaysContentTouches = NO;
_scrollView.delegate = self;
diff --git a/package.json b/package.json
index 05044f1f..4f13ee76 100644
--- a/package.json
+++ b/package.json
@@ -30,6 +30,7 @@
"releaseNext": "release-it --npm.tag=next --preRelease=rc",
"example": "yarn --cwd example",
"bootstrap": "yarn example && yarn && yarn example pods",
+ "bootstrap-fabric": "yarn example && yarn && RCT_NEW_ARCH_ENABLED=1 yarn example pods",
"bootstrap-no-pods": "yarn example && yarn",
"test:e2e:android": "bash ./scripts/run-maestro-tests.sh android",
"run-example-android": "cd example;react-native run-android --variant=release",
@@ -118,9 +119,18 @@
"useTabs": false
},
"codegenConfig": {
- "name": "RNCViewPager",
- "type": "components",
- "jsSrcsDir": "src"
+ "libraries": [
+ {
+ "name": "RNCViewPager",
+ "type": "components",
+ "jsSrcsDir": "src/PagerViewNativeComponent"
+ },
+ {
+ "name": "LEGACY_RNCViewPager",
+ "type": "components",
+ "jsSrcsDir": "src/LEGACY_PagerViewNativeComponent"
+ }
+ ]
},
"react-native-builder-bob": {
"source": "src",
diff --git a/src/LEGACY_PagerViewNativeComponent/LEGACY_PagerViewNativeComponent.ts b/src/LEGACY_PagerViewNativeComponent/LEGACY_PagerViewNativeComponent.ts
new file mode 100644
index 00000000..4770da9f
--- /dev/null
+++ b/src/LEGACY_PagerViewNativeComponent/LEGACY_PagerViewNativeComponent.ts
@@ -0,0 +1,81 @@
+/*
+ Note: The types below are duplicated between this file and `src/PagerViewNativeComponent/PagerViewNativeComponent.ts`.
+
+ This is on purpose. Firstly, we're declaring two native modules with two different iOS implementation flavors, but the same API.
+ Secondly, as these files serve as a reference point for React Native's new architecture Codegen process (which takes care of the
+ automatic generation of the native modules) we cannot extract the types into a separate file, or declare both native modules
+ in one file, as Codegen supports neither of these workarounds at the time of writing.
+
+ In order to make things as intuitive as possible, the duplicated types in this file are *not* exported, as they are meant for use
+ in this file only, by Codegen-related functions.
+*/
+import type * as React from 'react';
+import type { HostComponent, ViewProps } from 'react-native';
+import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands';
+import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
+
+import type {
+ DirectEventHandler,
+ Double,
+ Int32,
+ WithDefault,
+} from 'react-native/Libraries/Types/CodegenTypes';
+
+type OnPageScrollEventData = Readonly<{
+ position: Double;
+ offset: Double;
+}>;
+
+type OnPageSelectedEventData = Readonly<{
+ position: Double;
+}>;
+
+type OnPageScrollStateChangedEventData = Readonly<{
+ pageScrollState: 'idle' | 'dragging' | 'settling';
+}>;
+
+interface NativeProps extends ViewProps {
+ scrollEnabled?: WithDefault;
+ layoutDirection?: WithDefault<'ltr' | 'rtl', 'ltr'>;
+ initialPage?: Int32;
+ orientation?: WithDefault<'horizontal' | 'vertical', 'horizontal'>;
+ offscreenPageLimit?: Int32;
+ pageMargin?: Int32;
+ overScrollMode?: WithDefault<'auto' | 'always' | 'never', 'auto'>;
+ overdrag?: WithDefault;
+ keyboardDismissMode?: WithDefault<'none' | 'on-drag', 'none'>;
+ onPageScroll?: DirectEventHandler;
+ onPageSelected?: DirectEventHandler;
+ onPageScrollStateChanged?: DirectEventHandler;
+ useLegacy?: WithDefault;
+}
+
+type PagerViewViewType = HostComponent;
+
+interface NativeCommands {
+ setPage: (
+ viewRef: React.ElementRef,
+ selectedPage: Int32
+ ) => void;
+ setPageWithoutAnimation: (
+ viewRef: React.ElementRef,
+ selectedPage: Int32
+ ) => void;
+ setScrollEnabledImperatively: (
+ viewRef: React.ElementRef,
+ scrollEnabled: boolean
+ ) => void;
+}
+
+export const LEGACY_PagerViewNativeCommands: NativeCommands =
+ codegenNativeCommands({
+ supportedCommands: [
+ 'setPage',
+ 'setPageWithoutAnimation',
+ 'setScrollEnabledImperatively',
+ ],
+ });
+
+export default codegenNativeComponent(
+ 'LEGACY_RNCViewPager'
+) as HostComponent;
diff --git a/src/PagerView.tsx b/src/PagerView.tsx
index 785c9791..d2bfec53 100644
--- a/src/PagerView.tsx
+++ b/src/PagerView.tsx
@@ -1,18 +1,24 @@
import React from 'react';
-import { Platform, Keyboard } from 'react-native';
+import { Platform, Keyboard, StyleProp, ViewStyle } from 'react-native';
import { I18nManager } from 'react-native';
-import type {
+import type * as ReactNative from 'react-native';
+
+import {
+ LEGACY_childrenWithOverriddenStyle,
+ childrenWithOverriddenStyle,
+} from './utils';
+
+import PagerViewNativeComponent, {
+ PagerViewNativeCommands,
OnPageScrollEventData,
OnPageScrollStateChangedEventData,
OnPageSelectedEventData,
-} from './PagerViewNativeComponent';
-import type * as ReactNative from 'react-native';
+ NativeProps as PagerViewProps,
+} from './PagerViewNativeComponent/PagerViewNativeComponent';
-import type { NativeProps as PagerViewProps } from './PagerViewNativeComponent';
-import { childrenWithOverriddenStyle } from './utils';
-import PagerViewView, {
- Commands as PagerViewCommands,
-} from './PagerViewNativeComponent';
+import LEGACY_PagerViewNativeComponent, {
+ LEGACY_PagerViewNativeCommands,
+} from './LEGACY_PagerViewNativeComponent/LEGACY_PagerViewNativeComponent';
/**
* Container that allows to flip left and right between child views. Each
@@ -55,10 +61,27 @@ import PagerViewView, {
* }
* ```
*/
-
export class PagerView extends React.Component {
private isScrolling = false;
- pagerView: React.ElementRef | null = null;
+ pagerView: React.ElementRef | null = null;
+
+ private get nativeCommandsWrapper() {
+ return this.props.useLegacy
+ ? LEGACY_PagerViewNativeCommands
+ : PagerViewNativeCommands;
+ }
+
+ private get deducedLayoutDirection() {
+ if (
+ !this.props.layoutDirection ||
+ //@ts-ignore fix it
+ this.props.layoutDirection === 'locale'
+ ) {
+ return I18nManager.isRTL ? 'rtl' : 'ltr';
+ } else {
+ return this.props.layoutDirection;
+ }
+ }
private _onPageScroll = (
e: ReactNative.NativeSyntheticEvent
@@ -92,13 +115,17 @@ export class PagerView extends React.Component {
}
};
+ private _onMoveShouldSetResponderCapture = () => {
+ return this.isScrolling;
+ };
+
/**
* A helper function to scroll to a specific page in the PagerView.
* The transition between pages will be animated.
*/
public setPage = (selectedPage: number) => {
if (this.pagerView) {
- PagerViewCommands.setPage(this.pagerView, selectedPage);
+ this.nativeCommandsWrapper.setPage(this.pagerView, selectedPage);
}
};
@@ -108,7 +135,10 @@ export class PagerView extends React.Component {
*/
public setPageWithoutAnimation = (selectedPage: number) => {
if (this.pagerView) {
- PagerViewCommands.setPageWithoutAnimation(this.pagerView, selectedPage);
+ this.nativeCommandsWrapper.setPageWithoutAnimation(
+ this.pagerView,
+ selectedPage
+ );
}
};
@@ -119,48 +149,55 @@ export class PagerView extends React.Component {
*/
public setScrollEnabled = (scrollEnabled: boolean) => {
if (this.pagerView) {
- PagerViewCommands.setScrollEnabledImperatively(
+ this.nativeCommandsWrapper.setScrollEnabledImperatively(
this.pagerView,
scrollEnabled
);
}
};
- private _onMoveShouldSetResponderCapture = () => {
- return this.isScrolling;
- };
-
- private get deducedLayoutDirection() {
- if (
- !this.props.layoutDirection ||
- //@ts-ignore fix it
- this.props.layoutDirection === 'locale'
- ) {
- return I18nManager.isRTL ? 'rtl' : 'ltr';
- } else {
- return this.props.layoutDirection;
+ render() {
+ // old iOS `UIPageViewController`-based implementation
+ if (Platform.OS === 'ios' && this.props.useLegacy) {
+ return (
+ {
+ this.pagerView = ref;
+ }}
+ style={this.props.style}
+ layoutDirection={this.deducedLayoutDirection}
+ onPageScroll={this._onPageScroll}
+ onPageScrollStateChanged={this._onPageScrollStateChanged}
+ onPageSelected={this._onPageSelected}
+ onMoveShouldSetResponderCapture={
+ this._onMoveShouldSetResponderCapture
+ }
+ children={LEGACY_childrenWithOverriddenStyle(this.props.children)}
+ />
+ );
}
- }
- render() {
+ const style: StyleProp = [
+ this.props.style,
+ this.props.pageMargin
+ ? {
+ marginHorizontal: -this.props.pageMargin / 2,
+ }
+ : null,
+ {
+ flexDirection: this.props.orientation === 'vertical' ? 'column' : 'row',
+ },
+ ];
+
+ // new iOS `UIScrollView`-based implementation, Android, and other platforms
return (
- {
this.pagerView = ref;
}}
- style={[
- this.props.style,
- this.props.pageMargin
- ? {
- marginHorizontal: -this.props.pageMargin / 2,
- }
- : null,
- {
- flexDirection:
- this.props.orientation === 'vertical' ? 'column' : 'row',
- },
- ]}
+ style={style}
layoutDirection={this.deducedLayoutDirection}
onPageScroll={this._onPageScroll}
onPageScrollStateChanged={this._onPageScrollStateChanged}
diff --git a/src/PagerViewNativeComponent.ts b/src/PagerViewNativeComponent/PagerViewNativeComponent.ts
similarity index 87%
rename from src/PagerViewNativeComponent.ts
rename to src/PagerViewNativeComponent/PagerViewNativeComponent.ts
index f102aa96..9017e535 100644
--- a/src/PagerViewNativeComponent.ts
+++ b/src/PagerViewNativeComponent/PagerViewNativeComponent.ts
@@ -1,7 +1,8 @@
import type * as React from 'react';
+import type { HostComponent, ViewProps } from 'react-native';
import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
-import type { HostComponent, ViewProps } from 'react-native';
+
import type {
DirectEventHandler,
Double,
@@ -35,6 +36,7 @@ export interface NativeProps extends ViewProps {
onPageScroll?: DirectEventHandler;
onPageSelected?: DirectEventHandler;
onPageScrollStateChanged?: DirectEventHandler;
+ useLegacy?: WithDefault;
}
type PagerViewViewType = HostComponent;
@@ -54,13 +56,14 @@ export interface NativeCommands {
) => void;
}
-export const Commands: NativeCommands = codegenNativeCommands({
- supportedCommands: [
- 'setPage',
- 'setPageWithoutAnimation',
- 'setScrollEnabledImperatively',
- ],
-});
+export const PagerViewNativeCommands: NativeCommands =
+ codegenNativeCommands({
+ supportedCommands: [
+ 'setPage',
+ 'setPageWithoutAnimation',
+ 'setScrollEnabledImperatively',
+ ],
+ });
export default codegenNativeComponent(
'RNCViewPager'
diff --git a/src/index.tsx b/src/index.tsx
index 1e7cbe3d..69abd0a7 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -7,7 +7,7 @@ import type {
OnPageSelectedEventData as PagerViewOnPageSelectedEventData,
OnPageScrollStateChangedEventData as PageScrollStateChangedNativeEventData,
NativeProps,
-} from './PagerViewNativeComponent';
+} from './PagerViewNativeComponent/PagerViewNativeComponent';
export type {
PagerViewOnPageScrollEventData,
diff --git a/src/utils.tsx b/src/utils.tsx
index 0167992a..0d7d265c 100644
--- a/src/utils.tsx
+++ b/src/utils.tsx
@@ -1,5 +1,22 @@
import React, { Children, ReactNode } from 'react';
-import { View } from 'react-native';
+import { StyleSheet, View } from 'react-native';
+
+export const LEGACY_childrenWithOverriddenStyle = (children?: ReactNode) => {
+ return Children.map(children, (child) => {
+ const element = child as React.ReactElement;
+ return (
+ // Add a wrapper to ensure layout is calculated correctly
+
+ {/* @ts-ignore */}
+ {React.cloneElement(element, {
+ ...element.props,
+ // Override styles so that each page will fill the parent.
+ style: [element.props.style, StyleSheet.absoluteFill],
+ })}
+
+ );
+ });
+};
export const childrenWithOverriddenStyle = (
children?: ReactNode,