关于flutter:flutter系列之移动端的手势基础GestureDetector

41次阅读

共计 5221 个字符,预计需要花费 14 分钟才能阅读完成。

简介

挪动的和 PC 端有什么不同呢?同样的 H5 能够运行在 APP 端,也能够运行在 PC 端。两者最大的区别就是挪动端能够用手势。手势能够做到一些比方左滑右滑,上滑下滑,缩放等操作。

原生的 andorid 和 IOS 当然能够做到这些事件, 作为一个挪动的的开发框架 flutter,天然也可能反对手势。flutter 中的手势反对叫做 GestureDetector,一起来看看 flutter 中的手势根底吧。

Pointers 和 Listener

咱们先来考虑一下最简略的手势是什么呢?很显著,最简略的手势就是模仿鼠标的点击操作。咱们能够将其称之为 Pointer event, 也就是各种点击事件。

flutter 中有四种 Pointer 事件,这些事件如下所示:

  • PointerDownEvent – 示意用手点击了屏幕,接触到了一个 widget。
  • PointerMoveEvent – 示意手指从一个地位挪动到另外一个地位。
  • PointerUpEvent – 手指从点击屏幕变成了来到屏幕。
  • PointerCancelEvent – 示意手指来到了该应用程序。

那么点击事件的传递机制是什么样的呢?

以手指点击屏幕的 PointerDownEvent 事件为例,当手指点击屏幕的时候,flutter 首先会去定位该点击地位存在的 widget, 而后将该点击事件传递给该地位的最小 widget.

而后点击事件从最新的 widget 向上开始冒泡,并将其分派到从最外面的 widget 到树根的门路上的所有 widget 中。

留神,flutter 中并没有勾销或进行进一步分派 Pointer 事件的机制。

要想监听这写 Pointer 事件,最简略间接的方法就是应用 Listener:

class Listener extends SingleChildRenderObjectWidget {
  /// Creates a widget that forwards point events to callbacks.
  ///
  /// The [behavior] argument defaults to [HitTestBehavior.deferToChild].
  const Listener({
    Key? key,
    this.onPointerDown,
    this.onPointerMove,
    this.onPointerUp,
    this.onPointerHover,
    this.onPointerCancel,
    this.onPointerSignal,
    this.behavior = HitTestBehavior.deferToChild,
    Widget? child,
  }) : assert(behavior != null),
       super(key: key, child: child);

能够看到 Listener 也是一种 widget,并且能够监听多种 Pointer 的事件。

咱们能够把要监听 Pointer 的 widget 封装在 Listener 中,这样就能够监听各种 Pointer 事件了,具体的例子如下:

Widget build(BuildContext context) {
    return ConstrainedBox(constraints: BoxConstraints.tight(const Size(300.0, 200.0)),
      child: Listener(
        onPointerDown: _incrementDown,
        onPointerMove: _updateLocation,
        onPointerUp: _incrementUp,
        child: Container(
          color: Colors.lightBlueAccent,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const Text('You have pressed or released in this area this many times:'),
              Text(
                '$_downCounter presses\n$_upCounter releases',
                style: Theme.of(context).textTheme.headline4,
              ),
              Text('The cursor is here: (${x.toStringAsFixed(2)}, ${y.toStringAsFixed(2)})',
              ),
            ],
          ),
        ),
      ),
    );

 void _incrementDown(PointerEvent details) {_updateLocation(details);
    setState(() {_downCounter++;});
  }

  void _incrementUp(PointerEvent details) {_updateLocation(details);
    setState(() {_upCounter++;});
  }

  void _updateLocation(PointerEvent details) {setState(() {
      x = details.position.dx;
      y = details.position.dy;
    });
  }

然而对于 Lisenter 来说只能监听最原始的 Pointer 事件,所以如果想监听更多类型的手势事件的话,则能够应用 GestureDetector.

GestureDetector

GestureDetector 能够检测上面这些手势,包含:

  1. Tap

Tap 示意的是用户点击的事件,Tap 有上面几种事件:

onTapDown
onTapUp
onTap
onTapCancel
  1. Double tap

Double tap 示意的是双击事件,Double tap 只有一种类型:

onDoubleTap
  1. Long press

Long press 示意的是长按。也只有上面一种类型:

onLongPress
  1. Vertical drag

Vertical drag 示意的是垂直方向的拉, 它有三个事件,别离是:

onVerticalDragStart
onVerticalDragUpdate
onVerticalDragEnd
  1. Horizontal drag

有垂直方向的拉,就有程度方向的拉,Horizontal drag 示意的是程度方向的拉, 它同样有三个事件,别离是:

onHorizontalDragStart
onHorizontalDragUpdate
onHorizontalDragEnd
  1. Pan

Pan 这个货色能够看做是 Vertical drag 和 Horizontal drag 的合集,因为有时候咱们是心愿同时能够程度或者垂直挪动, 在这种状况上面,咱们就须要应用到 Pan 的事件:

onPanStart
onPanUpdate
onPanEnd

留神,Pan 是和独自的 Vertical drag、Horizontal drag 是互相抵触的,不能同时应用。

要想监听下面的这些事件,咱们能够应用 GestureDetector,先看下 GestureDetector 的定义:

class GestureDetector extends StatelessWidget {
  GestureDetector({
    Key? key,
    this.child,
    this.onTapDown,
    this.onTapUp,
    this.onTap,
    this.onTapCancel,
    this.onSecondaryTap,
    this.onSecondaryTapDown,
    this.onSecondaryTapUp,
    this.onSecondaryTapCancel,
    this.onTertiaryTapDown,
    this.onTertiaryTapUp,
    this.onTertiaryTapCancel,
    this.onDoubleTapDown,
    this.onDoubleTap,
    this.onDoubleTapCancel,
    this.onLongPressDown,
    this.onLongPressCancel,
    this.onLongPress,
    this.onLongPressStart,
    this.onLongPressMoveUpdate,
    this.onLongPressUp,
    this.onLongPressEnd,
    this.onSecondaryLongPressDown,
    this.onSecondaryLongPressCancel,
    this.onSecondaryLongPress,
    this.onSecondaryLongPressStart,
    this.onSecondaryLongPressMoveUpdate,
    this.onSecondaryLongPressUp,
    this.onSecondaryLongPressEnd,
    this.onTertiaryLongPressDown,
    this.onTertiaryLongPressCancel,
    this.onTertiaryLongPress,
    this.onTertiaryLongPressStart,
    this.onTertiaryLongPressMoveUpdate,
    this.onTertiaryLongPressUp,
    this.onTertiaryLongPressEnd,
    this.onVerticalDragDown,
    this.onVerticalDragStart,
    this.onVerticalDragUpdate,
    this.onVerticalDragEnd,
    this.onVerticalDragCancel,
    this.onHorizontalDragDown,
    this.onHorizontalDragStart,
    this.onHorizontalDragUpdate,
    this.onHorizontalDragEnd,
    this.onHorizontalDragCancel,
    this.onForcePressStart,
    this.onForcePressPeak,
    this.onForcePressUpdate,
    this.onForcePressEnd,
    this.onPanDown,
    this.onPanStart,
    this.onPanUpdate,
    this.onPanEnd,
    this.onPanCancel,
    this.onScaleStart,
    this.onScaleUpdate,
    this.onScaleEnd,
    this.behavior,
    this.excludeFromSemantics = false,
    this.dragStartBehavior = DragStartBehavior.start,
  })

能够看到 GestureDetector 是一个无状态的 Widget,它和 Listner 一样,能够承受一个 child Widget,而后监听了很多手势的事件。

所以,一般来说,咱们这样来应用它:

GestureDetector(onTap: () {setState(() {
                  // Toggle light when tapped.
                  _lightIsOn = !_lightIsOn;
                });
              },
              child: Container(
                color: Colors.yellow.shade600,
                padding: const EdgeInsets.all(8),
                // Change button text when light changes state.
                child: Text(_lightIsOn ? 'TURN LIGHT OFF' : 'TURN LIGHT ON'),
              ),
            ),

留神,如果 GestureDetector 中有 child,那么 onTap 的作用范畴就在子 child 的范畴。如果 GestureDetector 中并没有 child,那么其作用范畴就是 GestureDetector 的父 widget 的范畴。

手势抵触

因为手势的监听有很多种形式,然而这些形式并不是齐全独立的,有时候这些手势可能是互相冲突的。比方后面咱们提到的 Pan 和 Vertical drag、Horizontal drag。

如果遇到这样的状况,那么 futter 会自行进行抵触解决,去抉择到底用户执行的是哪个操作。

比方,当用户同时进行程度和垂直拖动的时候,两个识别器在接管到指针向下事件时都会开始察看指针挪动事件。

如果指针程度挪动超过肯定数量的逻辑像素,则程度识别器获胜,而后将该手势解释为程度拖动。相似地,如果用户垂直挪动超过肯定数量的逻辑像素,则垂直识别器获胜。

总结

手势辨认是挪动端的劣势我的项目,大家能够尝试在须要的中央应用 GestureDetector,能够达到意想不到的用户成果哦。

更多内容请参考 http://www.flydean.com/05-flutter-gestures/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

欢送关注我的公众号:「程序那些事」, 懂技术,更懂你!

正文完
 0