Flutter 手势在多指触摸时一些方法会多次触发

1,180 阅读4分钟

[》跳过拾光记忆]

拾光记忆

1. Flutter 项目资产管理,看这一篇就够了!

简介: 针对 Flutter 项目资产管理的脚本服务。Fam 具有以下特点: 支持多种平台以及各平台无差异化、界面美观、功能齐全、快捷方便。
推荐: ⭐️⭐️⭐️⭐️⭐️

[返回拾光记忆《]

IDKitGestureRecognizer.png

一、简述

Flutter 开发中手势处理的小部件有 GestureRecognizerListener 两个比较简单、常用的小部件。其中 GestureRecognizer 是我们经常使用的,能够满足日常开发简单手势检测。但是它在监控多个手指事件时会连带触发一些与多个手指不相关的方法。下面我用一个简单的例子来说明问题。

二、问题验证

例如: 现有一个小部件需要移动、缩放、点击、多指检测等功能时,我们首先想到使用 GestureRecognizer 小部件来实现。代码如下:

import 'dart:developer';
import 'package:flutter/material.dart';

class TestApp extends StatelessWidget {
  const TestApp({super.key});

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTapDown: (details) => log('--- onTapDown'),
      onTapUp: (details) => log('--- onTapUp'),
      onTapCancel: => log('--- onTapCancel'),
      onScaleStart: (details) => log('--- onScaleStart'),
      onScaleUpdate: (details) => log('--- onScaleUpdate'),
      onScaleEnd: (details) => log('--- onScaleEnd'),
      child: Container(
        color: Colors.red,
        child: const Text('小部件'),
      ),
    );
  }
}
  1. 手指垂直按下和抬起,上面代码打印输出如下:

    [log] --- onTapDown
    [log] --- onTapUp
    

    从上面打印,单点事件的处理是没有问题的。

  2. 手指按下并移动并抬起,上面代码打印输出如下:

    [log] --- onTapDown
    [log] --- onTapCancel
    [log] --- onScaleStart
    [log] --- onScaleUpdate
    [log] --- onScaleEnd
    

    从上面打印来看,我们本想手指移动只打印和手指移动相关的事件回调即可。但是它还输出了点击按下点击取消的手势事件的回调。

  3. 手指直接移动并抬起,上面代码打印输出如下:

    [log] --- onScaleStart
     31 [log] --- onScaleUpdate
    [log] --- onScaleEnd
    

    从上面打印,手势直接移动事件的处理是没有问题的。

  4. 两指缩放时,上面代码打印输出如下:

    [log] --- onTapDown
    [log] --- onTapCancel
    [log] --- onScaleStart
     155 [log] --- onScaleUpdate
    [log] --- onScaleEnd
    [log] --- onScaleStart
     2 [log] --- onScaleUpdate
    [log] --- onScaleEnd
    

    从上面打印来看,我们本想进行手势缩放操作,然后缩放先关手势回调即可。但是它也触发点击手势的方法以及缩放结束时会多次调用手势缩放相关的方法。

  5. 三指同时点击屏幕然后移动并抬起,上面代码打印输出如下:

    [log] --- onTapDown
    [log] --- onTapCancel
    [log] --- onScaleStart
     415 [log] --- onScaleUpdate
    [log] --- onScaleEnd
    [log] --- onScaleStart
    [log] --- onScaleUpdate
    [log] --- onScaleEnd
    [log] --- onScaleStart
    [log] --- onScaleUpdate
    [log] --- onScaleEnd
    

    从上面打印来看,进行手势缩放操作,它也触发点击手势的方法以及缩放结束时会几个手指会调用几次手势缩放相关的方法。

总结: 从上面的我们相关的测试结果来看,系统的 GestureRecognizer 在某些功能时会触发该功能之外的事件回调方法。那Flutter 有没有现有小部件能解决这个问题呢?答案是有的

三、IDKitGestureRecognizer

  1. 简介

    IDKitGestureRecognizeridkit 库里面的小部件。该小部件目前支持 手势压感检测手指数量检测手指点击手指缩放、移动 等事件的回调。

  2. 方法

    • Function(SerialTapUpDetails)? onTap
      手指点击方法的回调函数

    • Function(ScaleStartDetails)? onStart
      手势缩放、移动方法开始的回调函数

    • Function(ScaleUpdateDetails)? onUpdate
      手势缩放、移动方法更新的回调函数

    • Function(ScaleEndDetails)? onEnd
      手势缩放、移动方法结束的回调函数

    • Function(int)? fingerCount
      有几个手指触摸屏幕检测事件的回调函数

    • Function(ForcePressDetails)? forcePressOnStart
      手指压感检测开始的回调函数

    • Function(ForcePressDetails)? forcePressOnUpdate
      手指压感检测更新的回调函数

    • Function(ForcePressDetails)? forcePressOnEnd
      手指压感检测结束的回调函数

  3. 演示

    将上面例子的代码中手势处理的小部件更换为 IDKitGestureRecognizer。首先您需要引入idkit 库,你只需要在项目根目录终端里执行 flutter pub add idkit 指令即可。 例子更换后的代码如下:

    import 'dart:developer';
    import 'package:app/gesture.dart';
    import 'package:flutter/material.dart';
    
    class TestApp extends StatelessWidget {
      const TestApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return IDKitGestureRecognizer(
          onTap: (p0) => log('-- onTap'),
          onStart: (p0) => log('-- onStart'),
          onUpdate: (p0) => log('-- onUpdate'),
          onEnd: (p0) => log('-- onEnd'),
          forcePressOnStart: (p0) => log('-- forcePressOnStart'),
          forcePressOnUpdate: (p0) => log('-- forcePressOnUpdate'),
          forcePressOnEnd: (p0) => log('-- forcePressOnEnd'),
          fingerCount: (p0) => log('-- fingerCount - 检测到 $p0 个手指'),
          child: Container(
            color: Colors.red,
            child: const Text('小部件'),
          ),
        );
      }
    }
    
  4. 验证

    • 点击小部件,上面代码打印输出为:

      [log] -- onTap
      
    • 点击并移动然后抬起,上面代码打印输出为:

      [log] -- onStart
       85 [log] -- onUpdate
      [log] -- onEnd
      
    • 3 个手指同时点击屏幕,上面代码打印输出为:

      [log] -- fingerCount - 检测到 3 个手指
      
    • 压力检测,上面代码打印输出为:

      [log] -- forcePressOnStart
       215 [log] -- forcePressOnUpdate
      [log] -- forcePressOnEnd
      

总结:IDKitGestureRecognizer 可以很好的处理 Flutter 监听多个手势时,触发某一项手势时,其他额外手势函数也会触发的问题。

四、idkit

idkit 是让开发变的更简单的开发包,它依托于 pub.dev 。它包含 Flutter 基本开发常用功能以及组件。欢迎您们的使用。便捷使用指令 flutter pub add idkit