Flutter 多引擎渲染,混合嵌套滚动探索
背景
前一段时间有个需求是在一个滚动复杂的 Native 页面(多级滚动嵌套)中,嵌入一个 Flutter 列表组件。
先说结论
Flutter + Native 混合嵌套体验并不好,且需要花费更多的维护成本。既然做不到降本增效,那也没必要做这种 KPI 式的事情。所以最后还是用 Native 的 scrollView
来落地。
但整个探索过程还是值得分享给各位同学了解一下。
过程
整体验证过程是在 iOS 上进行的(毕竟笔者是个 iOSer [手动狗头])。
还有一点要说一下测试工程找不到了 ... 只有当时文档上留的一些截图,所以没办法直接代码上加注释。
提前做
在 iOS 上,FlutterView
响应优先级很低,Flutter 响应的是 touch
相关事件,会被上层的手势拦截,如果上层有滑动或者点击事件就会产生 Flutter
操作上无响应的问题。
(关于 Flutter 响应原理这里不过多阐述,有兴趣的同学可以找一下相关的文章)
解决方式上,在 FlutterViewController
上增加常用的点击、滑动等手势,来保证 FlutterView
作为子视图能优先响应而不被父视图上的手势事件拦截。
- (void)setupGestureRecognizer {
// 增加滑动手势
UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] init];
panGestureRecognizer.cancelsTouchesInView = NO;
[self.flutterViewController.view addGestureRecognizer:panGestureRecognizer];
// 增加点击手势
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] init];
tapGestureRecognizer.cancelsTouchesInView = NO;
[self.flutterViewController.view addGestureRecognizer:tapGestureRecognizer];
}
方案一:各自处理滚动
Native 的 UIScrollView
和 FlutterView
是相互独立,处理自身滚动。
适用场景:不需要惯性联动的场景(比如上滑后吸顶,再次滑动再进行 flutter 滚动)。
关键测试代码如下:
测试上,超过一定滚动距离就禁用 Native UIScrollView
滚动,再次滚动时, FlutterView
就会响应并滚动。
好处是不需要什么冲突处理。当然在需要联动场景,就是完全的撕裂,不符合我们的要求。
方案二:Native 控制,Flutter 跟随
Native UIScrollView
响应手势事件, Flutter
根据 messageChannel
实时传输的滚动距离跟随滚动。
关键测试代码如下:
gridViewComponent
是测试用的 Flutter UI 滚动组件,提供了一个封装好的 scrollTo
方法,内部是 messageChannel
进行通信。
原理简单的说,就是 FlutterView
不响应手势,滚动由外部 UIScrollView
统一控制,FlutterView
反馈给 iOS 当前内部滚动的状态。
优点:
能跟现有 Native 代码较好的融合,也不需要更多的改造现有代码逻辑。
缺点:
- 割裂了 Flutter 的完整性,Flutter 需要增加更多的逻辑判断(比如滚动是否到底,加载更多可能也不能用第三方库)。
- (需测试)
messageChannel
通信上性能不算太好,可能要验证各类机型是否会出现抖动问题。
方案三:Flutter 控制,Native 跟随
FlutterView
响应手势事件,获取到的滚动参数,回传给 Native,来控制 UIView
的布局位置。
关键测试代码如下:
gridViewComponent
提供了一个封装好的 handleScroll
的回调方法,把滚动 Y 轴信息传回 Native,Native 重新布局 UIView
。
效果如下:
可以看到小绿块(UIView
)位置确实在跟随 FlutterView
滚动变化。
优点:FlutterView
逻辑上更完整。
缺点:在 Native 上要处理更多的逻辑。
后续
在 Android 上还有另一个问题,Android 设备种类繁多,各种魔改,比如 Flutter 在 Android 华为设备存在滚动惯性跟其他机型不一致的问题,惯性偏短。
所以结论上,Flutter 多引擎渲染来做部分嵌套滚动不大可行。需要踩更多的坑。
如果对你开发学习上有丝丝作用,请点个赞[开心] ~