Skip to content

Commit

Permalink
feat(iOS): Add a useLegacy flag to switch between the old/new iOS i…
Browse files Browse the repository at this point in the history
…mplementation (#783)

* wip: unsuspicious changes

* wip: unsuspicious changes v2

* FABRIC NEW IMPL -> OLD IMPL

* wip: bring back useLegacy on the RN side

* wip: bring back duplicate types to fix codegen issues

* wip: remove #705 related code for now

* wip: old/new impl division first draft

* wip: old/new impl division continued

* wip: old/new impl v3

* wip: add a `LEGACY_` prefix to all legacy implementation-related symbols

* wip: fix styles for new implementation on Fabric

* wip: move old/new impl into separate folders

* wip: fix old impl fabric symbol names

* wip: xcode changes

* wip: clean up & unify the naming convention

* wip: fix linter issues

* wip: fix styles for new implementation on Paper

* wip: make Fabric example run on another port by default to make it possible to run both examples in parallel

* wip: implement an abstraction over native commands invocations to reduce branching

* refactor: remove the unnecessary value for boolean props

* fix: bump react-native-safe-area-context to a Fabric-enabled version

* feat: bring back & adjust the `bootstrap-fabric` script

* feat: adjust the home screen title depending on the used architecture

* chore: update example/Podfile.lock

* chore: update an Xcode project file after building

* ci: make next branch events trigger ios/android build workflows

* chore: remove commented-out code related to #705 for now

* chore: add legacy implementation explanation comment

* wip: Android fixes

* fix: unnecessary comma in MainActivity.java

* feat: readme makeover

* chore: bump react-native-screens & react-native-gesture-handler in example

* refactor(android): extract module name to shared variable, add comment for context

* chore: remove unnecessary yarn.lock deps

* chore(ios): bring back removed build flags

* chore(ios): remove unnecessary concurrentRootEnabled method

According to React Native Upgrade Helper, this method is to be removed when updating to RN 0.72:
https://react-native-community.github.io/upgrade-helper/?from=0.71.14&to=0.72.0#RnDiffApp-ios-RnDiffApp-AppDelegate.mm

* fix(android): adjust incorrect param type on Fabric

* chore: remove unnecessary tsconfig.json comment

* chore(ios): bring back (currently unused) code related to #712 and #705
  • Loading branch information
igorbej authored Dec 21, 2023
1 parent 08486ba commit c8cc208
Show file tree
Hide file tree
Showing 33 changed files with 1,589 additions and 185 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ on:
pull_request:
branches:
- master
- next
paths:
- '.github/workflows/android.yml'
- 'android/**'
- 'example/android/**'
push:
branches:
- master
- next

concurrency:
group: ${{ github.ref }}-android
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ on:
pull_request:
branches:
- master
- next
paths:
- '.github/workflows/ios.yml'
- 'ios/**'
- 'example/ios/**'
push:
branches:
- master
- next

concurrency:
group: ${{ github.ref }}-ios
Expand Down
87 changes: 74 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

<br/>
<p align="center">
Expand All @@ -17,22 +20,80 @@ This component allows the user to swipe left and right through pages of data. Un

<br/>

## 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

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
@@ -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<FrameLayout>() {
override fun getName() = LEGACY_PagerViewViewManagerImpl.NAME

override fun createViewInstance(context: ThemedReactContext): FrameLayout {
throw Error("LEGACY_RNCViewPager is an iOS-only feature")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,11 @@ class PagerViewViewManager : ViewGroupManager<NestedScrollableHost>(), 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
Expand Down
Original file line number Diff line number Diff line change
@@ -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"
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ class PagerViewPackage : ReactPackage {
}

override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
return listOf(PagerViewViewManager())
return listOf(PagerViewViewManager(), LEGACY_PagerViewViewManager())
}
}
Original file line number Diff line number Diff line change
@@ -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<FrameLayout>() {
override fun getName() = LEGACY_PagerViewViewManagerImpl.NAME

override fun createViewInstance(context: ThemedReactContext): FrameLayout {
throw Error("LEGACY_RNCViewPager is an iOS-only feature")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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?
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
17 changes: 9 additions & 8 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -770,14 +771,14 @@ 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
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a

PODFILE CHECKSUM: 3875acd7cb7e8f7782e244f1db71aa5f14571810

COCOAPODS: 1.13.0
COCOAPODS: 1.12.1
7 changes: 4 additions & 3 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand All @@ -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",
Expand Down
12 changes: 12 additions & 0 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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' },
Expand Down Expand Up @@ -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 (
Expand Down Expand Up @@ -101,6 +110,9 @@ export function Navigation() {
name="PagerView Example"
component={App}
options={{
title: global?.nativeFabricUIManager
? 'PagerView Example (Fabric)'
: 'PagerView Example',
headerRight: () => (
<Button
onPress={() =>
Expand Down
Loading

0 comments on commit c8cc208

Please sign in to comment.