React Navigation 如何做到使用原生的 View Controller 来做 navigation 的?

2022-02-13 16:27:45 +08:00
 FaiChou

已经有段时间没有写 RN, 之前用 Navigation 还是 2.x 版本, 现在已经 6.x .

看到RN 官方有这一段:

This native-stack navigator uses the native APIs: UINavigationController on iOS and Fragment on Android so that navigation built with createNativeStackNavigator will behave the same and have the same performance characteristics as apps built natively on top of those APIs.

比较疑惑, RN 不是只有一个 RootView 吗? (rootViewController.view = rootView)

之前页面跳转(RN 里面)都是 Navigation 库给做的转场动画, 现在 它是怎么实现的用原生的 API 来做跳转?

猜测: ViewController 如果没有原生的 Navigation 只能 present, 不能 push/pop; 所以应该是做了某些魔法操作, 当用户使用 native-stack 的情况下, 在原生里添加的一层 Navigation.

但具体是怎么做的呢?

1659 次点击
所在节点    iOS
3 条回复
Bijiabo
2022-02-13 16:56:53 +08:00
将 NavigationController 的 View 作为 child view ,可以仔细分析一下 react-native-screens 中的 `RNSScreenStack.m`

在 SDK 中将继承自 `UINavigationController` 的 `RNScreensNavigationController` 作为原生导航管理用途,将 RNScreensNavigationController 的 View 作为 RNSScreenNavigationContainer 的 Native UI Component 的子 View ,大概是这样的。
FaiChou
2022-02-13 17:32:03 +08:00
@Bijiabo 谢谢回复. 还是有几个问题:

```
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:@"AwesomeProject"
initialProperties:nil];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
```

这是使用 RN 创建的项目, 里面只有一个 rootViewController. 它是如何(在哪里)实现 `将 NavigationController 的 View 作为 child view` 的? 是不是在编译 .h .m 时候给替换掉了? 具体是怎么完成的?

在 js 里写了很多 view, 使用原生的 navigation 跳转新的页面, 数据传输不会有影响吧? RN 的 js 那边都是一个 runtime, 比如要 push 新的页面, 在原生端得有一个 Controller 的生命周期, didLoad 后再将 RN 的 view 设置为它的 view? 还需要 bridge 来获取 RN 的 view 吗?
Bijiabo
2022-02-13 19:43:14 +08:00
@FaiChou

关于这个问题: 这是使用 RN 创建的项目, 里面只有一个 rootViewController. 它是如何(在哪里)实现 `将 NavigationController 的 View 作为 child view` 的? 是不是在编译 .h .m 时候给替换掉了? 具体是怎么完成的?


看到你的问题顺手看了一下 react-native-screens ,目前初步判断是这样的,可能不够准确。可以在 `RNSScreenStack.m` 中看到:

- 具体实现应该是对应此文件 249 行的 `[self addSubview:controller.view];`
- 这个 Native UI Component 封装实现了 `- (void)insertReactSubview:(RNSScreenView *)subview atIndex:(NSInteger)atIndex` 这个方法,可以拿到 JSX 中嵌套的子组件,渲染在 UINavigationController 中的子 controller 中

------

数据传输应该不会受到影响,目前还没遇到这方面的明显问题。看到现在新的 Fabric 布局引擎是基于 JSI 来做通讯的,不需要通过走 Bridge 的方式复制大量数据了。

关于生命周期这块不是看的很清楚(没仔细看,先做家务去 T_T...),应该是在 Native UI Component 首次渲染的时候设定为 child view 的。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/833558

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX