返回

巧用FlutterViewController,化解原生弹窗触碰烦恼**

IOS

摘要:

原生弹窗与Flutter内容共存时,弹窗触碰事件往往被Flutter响应,导致交互混乱。本文将深入探讨这一问题,并通过剖析FlutterViewController源码,提供一种巧妙的解决方案,让原生弹窗的触碰事件得到正确的处理。

关键词:

正文:

问题

在Flutter应用中,原生弹窗和Flutter内容常常并存,例如在Flutter界面中弹出原生对话框。然而,当用户触碰原生弹窗时,事件会被底层的Flutter内容响应,导致原生弹窗无法正常交互,出现错乱现象。

原因分析:

深入研究FlutterViewController源码,我们发现以下原因:

  1. FlutterViewController使用hitTest方法处理触碰事件。当原生弹窗被点击时,hitTest方法会优先返回Flutter控件,导致事件被Flutter响应。
  2. Flutter的事件处理机制遵循冒泡原则,事件会被逐层向上传递,直至被某个控件处理。由于Flutter控件优先获得事件,原生弹窗的事件无法到达底层。

解决方案:

为了解决这个问题,需要让原生弹窗的事件能够正确到达底层,而不被Flutter控件拦截。一种可行的方案是修改FlutterViewController的hitTest方法:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    // 自定义hitTest逻辑,优先返回原生弹窗视图
    if ([self.nativePopupView containsPoint:point]) {
        return self.nativePopupView;
    }

    // 否则,按默认逻辑处理
    return [super hitTest:point withEvent:event];
}

通过重写hitTest方法,当原生弹窗视图包含触碰点时,优先返回原生弹窗视图。这样,触碰事件将直接到达原生弹窗,从而解决交互混乱的问题。

代码示例:

以iOS为例,实现自定义hitTest方法的代码如下:

import Flutter

class MyFlutterViewController: FlutterViewController {
    var nativePopupView: UIView?

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 初始化原生弹窗视图...
    }

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        if nativePopupView?.frame.contains(point) ?? false {
            return nativePopupView
        }
        
        return super.hitTest(point, with: event)
    }
}

其他注意事项:

  1. 确保原生弹窗视图的层级高于Flutter视图。
  2. 在原生弹窗关闭后,记得释放对原生弹窗视图的引用,以避免内存泄漏。

总结:

通过修改FlutterViewController的hitTest方法,我们巧妙地解决了原生弹窗触碰事件被Flutter响应的问题。这种解决方案既优雅又高效,充分利用了FlutterViewController的自定义能力。通过遵循这些步骤,开发人员可以轻松解决交互问题,打造流畅无缝的原生弹窗体验。