Introduction

What's the difference between mobile and PC? The same H5 can run on the APP side or on the PC side. The biggest difference between the two is that the mobile terminal can use gestures. Gestures can do some operations such as swipe left and right, swipe up and down, zoom and so on.

Native andorid and IOS can of course do these things. As a mobile development framework, flutter can naturally support gestures. The gesture support in flutter is called GestureDetector, let's take a look at the gesture basics in flutter.

Pointers and Listeners

Let's first consider what is the simplest gesture? Obviously, the simplest gesture is to simulate a mouse click. We can call it Pointer event, that is, various click events.

There are four kinds of Pointer events in flutter, these events are as follows:

  • PointerDownEvent -- Indicates that the screen is clicked with the hand and a widget is touched.
  • PointerMoveEvent -- Indicates that the finger moves from one location to another.
  • PointerUpEvent -- The finger changed from tapping the screen to leaving the screen.
  • PointerCancelEvent -- Indicates that the finger has left the application.

So what is the delivery mechanism of the click event?

Taking the PointerDownEvent event of the finger click on the screen as an example, when the finger clicks on the screen, flutter will first locate the widget that exists at the clicked position, and then pass the click event to the smallest widget at that position.

The click event then bubbles up from the newest widget and dispatches it to all widgets on the path from the innermost widget to the root of the tree.

Note that there is no mechanism in flutter to cancel or stop further dispatch of Pointer events.

To listen to the Pointer event, the easiest and most direct way is to use a 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);

You can see that the Listener is also a widget, and can listen to various Pointer events.

We can encapsulate the widget to monitor Pointer in Listener, so that we can monitor various Pointer events. The specific example is as follows:

 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;
    });
  }

But for Listener, it can only listen to the most primitive Pointer events, so if you want to listen to more types of gesture events, you can use GestureDetector.

GestureDetector

GestureDetector can detect the following gestures, including:

  1. Tap

Tap represents the event that the user clicks. Tap has the following events:

 onTapDown
onTapUp
onTap
onTapCancel
  1. Double tap

Double tap represents a double-click event, and Double tap has only one type:

 onDoubleTap
  1. long press

Long press means a long press. There is only one type of:

 onLongPress
  1. Vertical drag

Vertical drag represents the vertical direction of the pull, it has three events, namely:

 onVerticalDragStart
onVerticalDragUpdate
onVerticalDragEnd
  1. Horizontal drag

There is a vertical pull, and there is a horizontal pull. Horizontal drag represents a horizontal pull. It also has three events, namely:

 onHorizontalDragStart
onHorizontalDragUpdate
onHorizontalDragEnd
  1. Pan

Pan can be seen as a collection of Vertical drag and Horizontal drag, because sometimes we want to move horizontally or vertically at the same time. In this case, we need to use the Pan event:

 onPanStart
onPanUpdate
onPanEnd
Note that Pan is in conflict with the separate Vertical drag and Horizontal drag, and cannot be used at the same time.

To monitor the above events, we can use GestureDetector, first look at the definition of 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,
  })

It can be seen that GestureDetector is a stateless Widget. Like Listner, it can accept a child Widget and then listen to many gesture events.

So, in general, we use it like this:

 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'),
              ),
            ),
Note that if there is a child in GestureDetector, then the scope of onTap is within the scope of the child child. If there is no child in GestureDetector, then its scope is the scope of GestureDetector's parent widget.

Gesture conflict

Because there are many ways to monitor gestures, but these methods are not completely independent, and sometimes these gestures may conflict with each other. For example, the Pan, Vertical drag and Horizontal drag we mentioned earlier.

If such a situation is encountered, then futter will resolve the conflict on its own to choose which operation the user performs.

For example, when the user drags both horizontally and vertically, both recognizers will start observing pointer move events when they receive a pointer down event.

If the pointer moves horizontally by more than a certain number of logical pixels, the horizontal recognizer wins, then interprets the gesture as a horizontal drag. Similarly, if the user moves vertically more than a certain number of logical pixels, the vertical recognizer wins.

Summarize

Gesture recognition is an advantageous project on the mobile terminal. You can try to use GestureDetector where you need it, and you can achieve unexpected user effects.

For more information, please refer to http://www.flydean.com/05-flutter-gestures/

The most popular interpretation, the most profound dry goods, the most concise tutorials, and many tricks you don't know are waiting for you to discover!

Welcome to pay attention to my official account: "Program those things", understand technology, understand you better!


flydean
890 声望432 粉丝

欢迎访问我的个人网站:www.flydean.com