Flutter事件拦截与分发,一次讲清楚。

        使用过flutter的朋友应该知道,flutter的事件处理是比较头疼的一个问题,主要是因为flutter的事件处理使用widget的实现的,每个widget之间是单独的个体,实现了数据隔离,而且事件也是由flutter的竞技场规则竞争实现获取,当一个widget获取到一个事件,必须等到该事件的一个完整的过程执行完成才会再次进行判定,完整的事件过程一般是手指动作:按下Down->移动Move(非必须)->抬起Up。只有等再次按下时才会进行下一次的竞技判定,这就极大的限制了我们开发的灵活性。

        那有上面这么多限制,是不是就不能实现事件完美的分发与拦截流程了呢?当然不是。

        我们要解决事件问题,我们首先要了解flutter中事件可以由那些widget获取。没错,我们一般都会用GestureDetector和Listeners实现。Listener事件是完全透过的,不管子widget如何处理,外层的父widget都能获取到事件。GestureDetector事件是可拦截的,当widget获取了事件,外层的父widget就不能获取到事件了,这里就相当于Android里面的事件拦截。我们主要说说GestureDetector,拦截很好处理,子widget处理事件便可拦截,看起来并没有什么问题,但是当你拦截到一半想让父widget获取事件怎么办?假设子widget在移动的过程中,想让父widget获取事件,这就很乏力了。Android给出的解决方案是事件分发,优先由父view向子view分发,我不分发给你,你连拦截的机会都没有,所以可以做到父view优先拦截。flutter可无法父widget优先拦截,因为父widget和子widget完全没有交互,他们数据根本就不互通,父widget根本无法获取子widget的状态,即使子widget把状态传给父widget,父widget也无法在一个子widget获取事件过程中开始一个完整的事件(一个完整的事件必须要有按下抬起动作)。

        所以思路是让父widget和子widget也一直拥有一个完整的事件过程,这样子widget和父widget传值刷新界面时,都能拥有完整的事件过程。该如何实现呢?我们拿垂直方向的滑动为例,直接上代码:

import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';

/// 当子widget拦截了事件时,外层无法获取Gesture时,该类可以帮助你获取外层的Gesture垂直方向事件,以便解决child事件冲突的影响
class KqVerticalDragGestureListener extends StatelessWidget {
  final Widget? child;
  final GestureDragUpdateCallback? onVerticalDragUpdate;

  const KqVerticalDragGestureListener(
      {super.key, required this.child, this.onVerticalDragUpdate});

  @override
  Widget build(BuildContext context) {
    return RawGestureDetector(gestures: {
      _MultipleVerticalDragGestureRecogniser:
          GestureRecognizerFactoryWithHandlers<
                  _MultipleVerticalDragGestureRecogniser>(
              () => _MultipleVerticalDragGestureRecogniser(),
              (_MultipleVerticalDragGestureRecogniser instance) {
        instance.onUpdate = (g) {
          onVerticalDragUpdate?.call(g);
        };
      })
    }, child: child);
  }
}

class _MultipleVerticalDragGestureRecogniser
    extends VerticalDragGestureRecognizer {
  @override
  void rejectGesture(int pointer) {
    //这句就是让该widget也能获取到事件
    acceptGesture(pointer);
  }
}

        一个事件竞技的过程中,是可以同时允许多个widget竞技成功的。即子widget获取事件的同时,父widget也能获取事件,让每个widget都能拥有一个完整的事件。当父widget获取到事件,便可以执行父widget想要执行的事件动作。

总结:1.Listener事件是透过的,不管子widget还是父widget,不管子widget获取未获取事件,大家都能获取事件 。

2.GestureDetector事件是竞技原则,子widget处理了事件,则优先获取事件,父widget便不可以获取事件。

3.对于GestureDetector,每个事件都需要一个完整的动作过程才能处理,必须有手指按下和手指抬起事件,手指滑动可有可无。一般来讲:按下Down->移动Move(非必须)->抬起Up。没有这样一个过程,事件是不可能触发的。

4.手势竞技是可以允许多个手势竞技成功的,即运行多个widget同时获取事件。

5.GestureDetector自身便可实现事件拦截,事件的分发需要自定义Recognizer主动加入竞技,让多个widget同时获取事件。

以上便是我对事件分发与拦截的一些理解,如果不足与理解错误,欢迎评论提出和指正。

你可能感兴趣的:(Dart,flutter,flutter,Dart)