虽然 react-native-navigation 是 Facebook React Native 官方文档推荐的导航库之一 ,但我也不得不说使用它做 APP 导航主框架的体验简直糟糕透了。当然,这本身可能就是 React Native 自身的问题。
1 react-native-navigation 简单分析
使用 react-native-navigation 首先得理解下它的实现。它独立于 RN Component 的 / 接口实现了一套自己的事件机制,最重要的可能是 /。它提供了一套页面堆栈操作和切换动画, 可以将目标页面切换到最上方, 可以返回上一页。
可能是为了性能或者设计使然, 的时候不会销毁当前页。也就是说,在 A 页面里 跳转到B 页面,不会 Unmount A 页面的。 不过在 B 页面 回 A 页面时,的确会 Unmount B 页面的。这也意味着,整个导航路径是一个页面堆栈,只要在堆栈里页面的 ,都不会被 Unmount。
2 页面堆栈的问题
这有时候会导致一些很严重的问题。有些情况下,特定的 可能会占用唯一的系统资源,比如:麦克风、照相机等。这些 在实现的时候往往只考虑了 React Native 的接口,在 的时候释放占用的资源。它们不会预料到与 react-native-navigation 的结合,专门提供一个 时释放资源的接口,而且有些情况下也未必能这样做。
如果 A 页面在使用这些 已经占用了麦克风或者相机,B 页面也要使用这些 ,那么从 A 跳转到 B 时,A 页面的资源不会被释放,B 页面就可能会遇到麦克风不可用,或者相机无法初始化等问题。
解决这个问题,最简单的办法是调整页面交互顺序,保证使用这些独占系统资源的页面永远在堆栈的最顶端,或者使用 Modal Stack,把独占资源的 放到 Modal 里去 present 然后 dismiss。
3 跨页跳转实现
react-native-navigation 只能支持页面堆栈,而且看起来只能支持 push/pop 一个页面,也就是说整个切换过程是串行的,push 顺序是 A->B->A->D ,那么 pop 顺序也只能是 D->A->B->A。
但很可惜地是,在产品经理眼中,是不存在串行页面切换这种限制的。TA 们有时候要求跳转的过程中没 A,但返回的时候要有 A;或者要求跳转的过程中有 A,但返回的时候可以跳过 A,或者甚至直接返回到堆栈最底端。
直接返回栈底很容易,react-native-navigation 提供了 popToRoot 接口,但它没有提供一下子 push 多个页面,或者一下子 pop 多个页面的功能。它也没有类似于 HTML5 的 history API,我们直接对堆栈进行操作,是不太可能的。只能通过它现有的接口想办法。
3.1 跨页 push
跳转的过程没有 A,但返回的时候要有 A,这只是一个产品需求。在实现上,是可以变成跳转过程中有 A,但是 A 被快速跳过,返回的时候才会被真正渲染。这样从用户体验上来看,并没有看到 A。代码实现上,可以考虑两种方法:
willAppear 结合 didDisappear 做状态控制
在 A 的 里放一个 状态,默认是 。 里判断 则直接跳转到下个页面, 里判断 则只渲染一个背景 ,否则才渲染正常页面。这样就实现了在页面切换过程中跳过 A。在 的 里将 置为 。这样在返回的时候 和 表现就和正常返回一样了。
willAppear 页面计数
在需要更复杂逻辑的地方,可以在 里放一个 计数器。在 里给计数器加一,这样每次进入页面都会增加计数。通过判断计数器的值,来决定如何 或者跳转。
3.2 跨页 pop
跳转的过程中有 A,但返回的时候要跳过 A,相当于可以自己操作 pop 的步长。很遗憾,react-native-navigation 没有提供这样的接口。不过我们可以采用一个 trick 的手段,来实现这个逻辑。
假设从 Root->A->B,在 A 的 里放一个 ,默认是 。 在 A 跳转到 B 时,通过 传入一个回调:,B 可以通过这个回调修改 A 的 state 为 ; 在 A 的 中,首先判断 是否为真,如果是真的话,代表是从 B 返回且 B 要求接力返回,那么 A 就直接 返回到 A 的上级。 B 在返回时,首先通过回调设置 为 ,然后再调用 接口,就实现了跨页返回。
领取专属 10元无门槛券
私享最新 技术干货