美文网首页iOS开发Flutter探索
Flutter开发-屏蔽Widget的多点触控行为

Flutter开发-屏蔽Widget的多点触控行为

作者: 泽泽伐木类 | 来源:发表于2020-07-18 00:23 被阅读0次

    前言

    在Flutter中我们在Widget实现一些手势交互通常会使用GestureDetector装饰器来实现,但是默认情况下,widget是支持多点触控,但是在一些特定需求下,我们不需要多点触控的操作,或者多点触控反而给一些功能带来麻烦,而且比较不方便的是,多点触控无法通过操作widget或者GestureDetector来屏蔽掉。查阅了官方文档发现的这个玩意:RawGestureDetector

    RawGestureDetector class

    A widget that detects gestures described by the given gesture factories.
    For common gestures, use a GestureRecognizer. RawGestureDetector is useful primarily when developing your own gesture recognizers.

    大概意思是:一个小部件,用于检测由给定手势工厂描述的手势。对于常用手势,请使用GestureRecognizer。 RawGestureDetector主要在开发自己的手势识别器时很有用。
    例如:

    RawGestureDetector(
      gestures: <Type, GestureRecognizerFactory>{
        TapGestureRecognizer: GestureRecognizerFactoryWithHandlers<TapGestureRecognizer>(
          () => TapGestureRecognizer(),
          (TapGestureRecognizer instance) {
            instance
              ..onTapDown = (TapDownDetails details) { setState(() { _last = 'down'; }); }
              ..onTapUp = (TapUpDetails details) { setState(() { _last = 'up'; }); }
              ..onTap = () { setState(() { _last = 'tap'; }); }
              ..onTapCancel = () { setState(() { _last = 'cancel'; }); };
          },
        ),
      },
      child: Container(width: 300.0, height: 300.0, color: Colors.yellow, child: Text(_last)),
    )
    

    我们可以通过RawGestureDetector来自定义手势。

    开始

    有时,你可能需要禁用多点触摸或在Flutter应用程序中点击小部件。 例如,有一个列表,并且一次只能单击其中一项。 您不希望用户同时用三个手指点击或触摸并立即选择三个项。基本上,您要防止用户多次点击或多点触摸。
    我们先创建一个简单的页面,页面加载一个ListView.builder(),

    import 'package:flutter/material.dart';
    import 'package:flutter/widgets.dart';
    
    class MyList extends StatelessWidget {
      List<String> myList = [
        "January",
        "February",
        "March",
        "April",
        "June",
        "July",
        "August"
      ];
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            body: Center(
                child: ListView.builder(
                    shrinkWrap: true,
                    itemCount: myList.length,
                    physics: ClampingScrollPhysics(),
                    itemBuilder: (BuildContext cxtListBuilder, int itemIdx) {
                      return ListTile(
                        title: Text(myList[itemIdx]),
                        onTap: () => print('tapped'),
                      );
                    })));
      }
    }
    

    这个列表上的cell都支持多点触控,效果图:
    【图】

    创建自定义手势识别器

    Flutter允许在GestureRecognizer基类的帮助下创建自定义手势识别器小部件。 该类已经有两个抽象的实现,可以实现多次轻击和单次轻击手势。

    单点触摸的实现

    首先创建一个自定义窗口小部件,以使其子窗口小部件只能具有单一触摸手势。

    class SingleTouchRecognizerWidget extends StatelessWidget {
      final Widget child;
      SingleTouchRecognizerWidget({this.child});
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return null;
      }
    }
    

    build()方法中,我们将返回仅支持单点触摸手势的手势检测器小部件。 因此,我们为此创建另一个名为_SingleTouchRecognizer的类

    class _SingleTouchRecognizer extends OneSequenceGestureRecognizer {
      @override
      // TODO: implement debugDescription
      String get debugDescription => null;
    
      @override
      void didStopTrackingLastPointer(int pointer) {
        // TODO: implement didStopTrackingLastPointer
      }
    
      @override
      void handleEvent(PointerEvent event) {
        // TODO: implement handleEvent
      }
    }
    

    现在我们回到我们的SingleTouchRecognizerWidget中,通过RawGestureDetector装饰器来定义我们刚才创建的单击手势检测器:

    class SingleTouchRecognizerWidget extends StatelessWidget {
      final Widget child;
      SingleTouchRecognizerWidget({this.child});
    
      @override
      Widget build(BuildContext context) {
        return RawGestureDetector(
          gestures: <Type, GestureRecognizerFactory>{
            _SingleTouchRecognizer: GestureRecognizerFactoryWithHandlers<_SingleTouchRecognizer>(
              () => _SingleTouchRecognizer(),
              (_SingleTouchRecognizer instance) {},
            ),
          },
          child: child,
        );
      }
    }
    

    现在,build()方法返回了一个RawGestureDetector,该RawGestureDetector处理_SingleTouchRecognizer类中的手势。接下来,我们需要在识别器类中实现这些方法。我们首先覆盖GestureRecognizeraddAllowedPointer方法。

    class _SingleTouchRecognizer extends OneSequenceGestureRecognizer {
    
      int _p = 0;
      @override
      void addAllowedPointer(PointerDownEvent event) {
        //first register the current pointer so that related events will be handled by this recognizer
        startTrackingPointer(event.pointer);
        //ignore event if another event is already in progress
        if (_p == 0) {
          resolve(GestureDisposition.rejected);
          _p = event.pointer;
        } else {
          resolve(GestureDisposition.accepted);
        }
      }
    ...
    

    在这里,startTrackingPointer方法注册了将由识别器处理的相关事件。 然后,resolve()负责确保是否允许继续进行触摸事件。

    解析参数

    如果我们传入GestureDisposition.rejected,则当前的触摸事件无法处理。 因此,此触摸事件将被传递并允许其继续。 但是,如果传递了GestureDisposition.accepted,则将解析触摸事件,并且不会再调用其他事件。
    通过handleEvent函数重置控制变量_p的值。

    ...
    @override
      void handleEvent(PointerEvent event) {
        if (!event.down && event.pointer == _p) {
          _p = 0;
        }
      }
    ...
    

    这样就完成了_SingleTouchRecognizer类的实现。
    现在,只需要将该Widget包裹在想要支持单点触控的widget外层即可。

    应用

    ...
    child: SingleTouchRecognizerWidget(
                    child: ListView.builder(
    
    ...
    

    参考文献:
    disable-multi-touch-on-a-widget-in-flutter
    api.flutter.dev

    相关文章

      网友评论

        本文标题:Flutter开发-屏蔽Widget的多点触控行为

        本文链接:https://www.haomeiwen.com/subject/bykphktx.html