Flutter在iOS平台上手势冲突解决方案

436 阅读1分钟

在Flutter与iOS混合开发中,当Flutter页面内包含可滚动的组件时,用户在iOS设备上使用手势滚动Flutter组件时,会触发iOS原生的侧滑返回手势,导致用户意外返回上一级页面。本发明提供了一种方法,有效避免了此类手势冲突,确保了Flutter组件和iOS系统之间的无缝交互。

image2024-8-19_16-17-44.png

在iOS平台内集成Flutter后,由于iOS和Flutter有各自的手势,当用手势操作Flutter页面时,由于iOS系统机制原因会优先使iOS的手势生效,导致Flutter滑动组件无法滑动,页面返回。

架构及逻辑流程:

image2024-8-19_16-57-3.png

为了解决Flutter和iOS返回手势冲突创建了ProxyGestureRecognizer(代理手势),他的作用如下

1、接收 iOS 触摸事件,并传递给 Flutter(cancelsTouchesInView 设置为 NO 即可)。

ProxyGestureRecognizer.cancelsTouchesInView = NO;

2、根据Flutter页面是否能滑动映射成代理手势是否可响应,isWorking 代表Flutter页面滑动状态,isWorking 为YES时代表Flutter页面在滑动,此时代理手势生效,返回手势失效

image2024-8-19_17-49-43.png 3、代理手势根据状态去和其他 iOS 侧滑返回手势竞争后续触摸事件的处理权。此方法可设置代理手势优先级大于返回手势。

[popGestureRecognizer requireGestureRecognizerToFail:ProxyGestureRecognizer];

Flutter侧代理手势设置:

class FlutterGestureTracker extends StatelessWidget {
  const FlutterGestureTracker({ Key? key,  this.child})
      : super(key: key);
  final Widget? child;

  @override
  Widget build(BuildContext context) {
    return RawGestureDetector(
      behavior: HitTestBehavior.translucent,
      gestures: {
        PointerTracker: GestureRecognizerFactoryWithHandlers<PointerTracker>(
          () => PointerTracker(), //constructor
          (PointerTracker instance) {
            //initializer
            instance.onStart = (_)=>BJLog.log('parent onStart');
            instance.onUpdate = (_)=>BJLog.log('parent onUpdate');
            instance.onEnd = (_)=>BJLog.log('parent onEnd');
          },
        )
      },
      child: child,
    );
  }
}

class PointerTracker extends PanGestureRecognizer {
  bool _flutterGestureIsWorking = false;
  @override
  void rejectGesture(int pointer) {
    super.rejectGesture(pointer);
      _flutterGestureIsWorking = true;
      _notify();
  }

  @override
  void acceptGesture(int pointer) {
    super.acceptGesture(pointer);
      _flutterGestureIsWorking = false;
      _notify();
  }


  void _notify() {
    BoostChannel.instance.sendEventToNative(BoostNavigator.instance.getTopPageInfo()?.uniqueId??'',{"event":"flutterGestureStateChanged","args":{"isWorking":_flutterGestureIsWorking}});
  }

}

用FlutterGestureTracker包裹控件即可。