Жест GestureDetector на основе взаимодействия с Flutter

Flutter

представлять

GestureDetector — это детектор жестов Flutter, который пытается распознать жесты, соответствующие его ненулевому обратному вызову. Если у этого компонента Widget есть дочерний виджет, его поведение при изменении размера будет соответствовать дочернему виджету. Если у него нет дочерних элементов управления, он будет увеличиваться, чтобы соответствовать родительскому элементу.

Детекторы жестов с невидимыми дочерними элементами управления по умолчанию игнорируют прикосновения; эту логику можно контролировать с помощью поведения. GestureDetector также прослушивает события доступности и сопоставляет их с обратными вызовами. Чтобы игнорировать события специальных возможностей, задайте для ExcludeFromSemantics значение true.

Система жестов во Flutter состоит из двух отдельных слоев. Первый уровень — это необработанные события указателя, которые описывают положение и движение указателей (например, касание, мышь и перо) на экране. Второй слой — это жесты, которые описывают семантические действия, состоящие из одного или нескольких движений указателя, таких как перетаскивание, масштабирование, двойной щелчок и длительное нажатие.

жест

Во Flutter жесты представляют собой семантические действия (такие как нажатия, перетаскивания и масштабирование), которые можно распознать по нескольким событиям отдельных указателей (возможно, даже по нескольким отдельным указателям). Полный жест может отправлять несколько событий, соответствующих жизненному циклу жеста (например, начало перетаскивания, обновление перетаскивания и конец перетаскивания):

  • нажмите

    • onTapDown указатель коснулся экрана в определенном месте
    • onTapUp указатель перестает касаться экрана в определенном месте
    • Срабатывает событие клика onTap
    • onTapCancel OnTapDown, вызванный предыдущим указателем, не вызовет событие щелчка.
  • Двойной клик

    • onDoubleTap Пользователь дважды быстро нажимает на экран в одном и том же месте.
  • нажимать

    • onLongPress указатель остается в контакте с экраном в течение длительного времени в одном и том же положении
  • вертикальное сопротивление

    • onVerticalDragStart указатель коснулся экрана и может начать двигаться вертикально
    • onVerticalDragUpdate Указатель соприкасается с экраном и перемещается вертикально.
    • onVerticalDragEnd Указатель, который касался экрана и двигался вертикально, больше не соприкасается с экраном и движется с определенной скоростью, когда перестает касаться экрана
  • Перетащите горизонтально

    • onHorizontalDragStart указатель коснулся экрана и может начать двигаться горизонтально
    • onHorizontalDragUpdate указатель соприкасается с экраном и перемещается горизонтально
    • onHorizontalDragEnd Указатель, который касался экрана и двигался горизонтально, больше не соприкасается с экраном и движется с определенной скоростью, когда перестает касаться экрана

отношения наследования

Object —> Diagnosticable —> DiagnosticableTree —> Widget —> StatelessWidget —> GestureDetector

Конструктор

 Draggable({Key key, 
 @required Widget child,
 @required Widget feedback,
 T data, 
 Axis axis,
 Widget childWhenDragging,
 Offset feedbackOffset: Offset.zero, 
 DragAnchor dragAnchor: DragAnchor.child, 
 Axis affinity, 
 int maxSimultaneousDrags,
 VoidCallback onDragStarted, 
 DraggableCanceledCallback onDraggableCanceled, 
 DragEndCallback onDragEnd, 
 VoidCallback onDragCompleted, 
 bool ignoringFeedbackSemantics: true }) 

Общие свойства

  • dragStartBehavior → DragStartBehavior Определяет, как обрабатывать поведение начала перетаскивания

  • excludeFromSemantics → bool Следует ли исключать эти жесты из семантического дерева.

    Например, жест длительного нажатия, используемый для отображения всплывающей подсказки, исключен, поскольку сама всплывающая подсказка непосредственно содержится в семантическом дереве, поэтому наличие жеста для ее отображения приведет к дублированию информации.

  • onDoubleTap → GestureTapCallback Пользователь быстро дважды коснулся экрана кнопкой «Домой» в одном и том же месте.

  • onForcePressEnd → GestureForcePressEndCallback Указатель больше не касается экрана.

  • onForcePressPeak → GestureForcePressPeakCallback Указатель соприкасается с экраном и нажимается с максимальной силой. Сила не менее ForcePressGestureRecognizer.peakPressure.

  • onForcePressStart → GestureForcePressStartCallback Указатель касается экрана и нажимает достаточно сильно, чтобы начать давление. Сила не менее ForcePressGestureRecognizer.startPressure.

  • onForcePressUpdate → GestureForcePressUpdateCallback Указатель соприкасается с экраном, предварительно прошел ForcePressGestureRecognizer.startPressure и либо движется в плоскости экрана, либо давит на экран с разной силой, либо одновременно нажимает на оба экрана.

  • onHorizontalDragCancel → GestureDragCancelCallback Указатель, который ранее вызывал onHorizontalDragDown, не завершил отмену.

  • onHorizontalDragDown → GestureDragDownCallback Указатель соприкоснулся с экраном через кнопку «Домой» и может начать двигаться горизонтально.

  • onHorizontalDragEnd → GestureDragEndCallback Указатель, который был в контакте с домашним экраном и перемещался горизонтально, больше не касается экрана и перемещается с определенной скоростью, когда перестает касаться экрана.

  • onHorizontalDragStart → GestureDragStartCallback Указатель соприкоснулся с экраном через кнопку «Домой» и начинает двигаться горизонтально.

  • onHorizontalDragUpdate → GestureDragUpdateCallback Указатель, который соприкасается с основной кнопкой и движется горизонтально, перемещается в горизонтальном направлении.

  • onLongPress → GestureLongPressCallback Вызывается при распознавании жеста длительного нажатия кнопки «Домой».

  • onLongPressEnd → GestureLongPressEndCallback Указатель, вызывавший долгое нажатие кнопки домой, перестал касаться экрана.

  • onLongPressMoveUpdate → GestureLongPressMoveUpdateCallback После долгого нажатия кнопки домой указатель перетащился.

  • onLongPressStart → GestureLongPressStartCallback Вызывается при распознавании жеста длительного нажатия кнопки «Домой».

  • onLongPressUp → GestureLongPressUpCallback Указатель, вызывавший долгое нажатие кнопки домой, перестал касаться экрана.

  • onPanCancel → GestureDragCancelCallback Указатель, который ранее запускал onPanDown, не завершился.

  • onPanDown → GestureDragDownCallback Указатель соприкоснулся с экраном через кнопку «Домой» и может начать двигаться.

  • onPanEnd → GestureDragEndCallback Указатель, который ранее соприкасался с экраном через кнопку домой и перемещался, больше не соприкасается с экраном и движется с определенной скоростью, когда перестает касаться экрана.

  • onPanStart → GestureDragStartCallback Точка касания соприкасается с экраном и начала двигаться.

  • onPanUpdate → GestureDragUpdateCallback Этот обратный вызов запускается каждый раз, когда меняется положение точки касания на экране.

  • onScaleEnd → GestureScaleEndCallback Указатель больше не касается экрана.

  • onScaleStart → GestureScaleStartCallback Стрелка, соприкасающаяся с экраном, установила фокус с начальной шкалой 1,0.

  • onScaleUpdate → GestureScaleUpdateCallback Указатель, касающийся экрана, указывает на новый фокус и/или масштаб.

  • onSecondaryTapCancel → GestureTapCancelCallback Указатель, который ранее вызывал onSecondaryTapDown, в конечном итоге не приведет к касанию.

  • onSecondaryTapDown → GestureTapDownCallback Указатель, который мог вызвать касание дополнительной кнопки, коснулся экрана в определенном месте.

  • onSecondaryTapUp → GestureTapUpCallback Указатель, который вызывает нажатие дополнительной кнопки, перестал касаться экрана в определенном месте.

  • onTap → GestureTapCallback Источник триггера события клика с главной кнопкой.

  • onTapCancel → GestureTapCancelCallback Указатель, который ранее активировался onTapDown, не вызывает касания.

  • onTapDown → GestureTapDownCallback Указатель, который мог вызвать касание кнопки «Домой», коснулся экрана в определенном месте.

  • onTapUp → GestureTapUpCallback Указатель, который вызывал бы нажатие кнопки «Домой», перестал касаться экрана в определенном месте.

  • onVerticalDragCancel → GestureDragCancelCallback Указатель, который ранее вызывал onVerticalDragDown, не завершился.

  • onVerticalDragDown → GestureDragDownCallback Указатель соприкоснулся с экраном через кнопку «Домой» и может начать двигаться вертикально.

  • onVerticalDragEnd → GestureDragEndCallback Указатель, который ранее соприкасался с начальным экраном и перемещался вертикально, больше не соприкасается с экраном и движется с определенной скоростью, когда перестает касаться экрана.

  • onVerticalDragStart → GestureDragStartCallback Указатель коснулся экрана через кнопку «Домой» и начал двигаться вертикально.

  • onVerticalDragUpdate → GestureDragUpdateCallback Указатель, который соприкасается с основной кнопкой и перемещается вертикально, перемещается в вертикальном направлении.

Общий метод

  • build (контекст BuildContext) → Виджет Создайте компоненты.
  • debugFillProperties (свойство DiagnosticPropertiesBuilder) → недействительно Добавьте дополнительные свойства, связанные с узлом.
  • createElement() → Элемент без состояния Создайте StatelessElement для управления положением этого компонента в дереве пользовательского интерфейса.

Пример использования

1. Щелчок, двойной щелчок, длительное нажатие события

Здесь в демо-версии GestureDetector используется для распознавания жестов в компоненте Container. После срабатывания соответствующего события имя события отображается на Контейнере.Чтобы увеличить область клика, Контейнер устанавливается на 200×200.Код такой:

import 'package:flutter/material.dart';

class GestureDetectorTestRoute extends StatefulWidget {
  @override
  _GestureDetectorTestRouteState createState() =>
      new _GestureDetectorTestRouteState();
}

class _GestureDetectorTestRouteState extends State<GestureDetectorTestRoute> {
  String _operation = "No Gesture detected!"; 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(
        title: Text("GestureDetectorTest"),
      ),
      body: Center(
        child: GestureDetector(
          child: Container(
            alignment: Alignment.center,
            color: Colors.blue,
            width: 200.0,
            height: 200.0,
            child: Text(
              _operation,
              style: TextStyle(
                  color: Colors.white,
                  fontSize: 14,
                  decoration: TextDecoration.none),
            ),
          ),
          onTap: () => updateText("onTap"), //单击
          onDoubleTap: () => updateText("onDoubleTap"), //双击
          onLongPress: () => updateText("onLongPress"), //长按
        ),
      ),
    );
  }

  //更新文本
  void updateText(String text) {
    setState(() {
      _operation = text;
    });
    //提示
    showSnackBar(text);
  }

  var _scaffoldKey = new GlobalKey<ScaffoldState>();

  void showSnackBar(String message) {
    var snackBar = SnackBar(
        content: Text(message),
        backgroundColor: Colors.lightGreen,
        duration: Duration(milliseconds: 400));
    _scaffoldKey.currentState.showSnackBar(snackBar);
  }
}

Схема эффекта выглядит следующим образом:

GestureDetector

Примечание. Если события onTap и onDoubleTap отслеживаются одновременно, когда пользователь инициирует событие касания, будет задержка около 200 миллисекунд. Это связано с тем, что когда пользователь щелкает, он, скорее всего, щелкнет еще раз, чтобы вызвать событие двойного щелчка, поэтому исходный код GestureDetector будет ждать 200 миллисекунд, чтобы определить, является ли это событием двойного щелчка. Если пользователь слушает только событие onTap (не прослушивая onDoubleTap), обратный вызов не имеет задержки.

2. Перетащите события

import 'package:flutter/material.dart';

class DragTest extends StatefulWidget {
  @override
  _DragTestState createState() => new _DragTestState();
}

class _DragTestState extends State<DragTest>
    with SingleTickerProviderStateMixin {
  double _top = 0.0; //距顶部的偏移
  double _left = 0.0; //距左边的偏移

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("DragTest"),
      ),
      body: Stack(
        children: <Widget>[
          Positioned(
            top: _top,
            left: _left,
            child: GestureDetector(
              child: CircleAvatar(
                  child: Text("Draggable Text", textAlign: TextAlign.center),
                  radius: 50),
              //手指按下时会触发此回调
              onPanDown: (DragDownDetails e) {
                //打印手指按下的位置(屏幕)
                print("用户手指按下:${e.globalPosition}");
              },
              //手指滑动时会触发此回调
              onPanUpdate: (DragUpdateDetails e) {
                //用户手指滑动时,更新偏移,重新构建
                setState(() {
                  _left += e.delta.dx;
                  _top += e.delta.dy;
                });
              },
              onPanEnd: (DragEndDetails e) {
                //打印滑动结束时在x、y轴上的速度
                print(e.velocity);
              },
            ),
          )
        ],
      ),
    );
  }
}

Схема эффекта выглядит следующим образом:

Drag

3. Масштабное событие

В дополнение к таким событиям, как щелчок/двойной щелчок/перетаскивание, GestureDetector может прослушивать события масштабирования. Ниже мы демонстрируем простой эффект масштабирования изображения, пример кода выглядит следующим образом:

class _ScaleTestRouteState extends State<_ScaleTestRoute> {
  double _width = 200.0; //通过修改图片宽度来达到缩放效果

  @override
  Widget build(BuildContext context) {
   return Center(
     child: GestureDetector(
        //指定宽度,高度自适应
        child: Image.asset("./images/sea.png", width: _width),
        onScaleUpdate: (ScaleUpdateDetails details) {
          setState(() {
            //缩放倍数在0.8到10倍之间
            _width=200*details.scale.clamp(.8, 10.0);
          });
        },
      ),
   );
  }
}

Схема эффекта выглядит следующим образом:

Scale

Суммировать

В этой статье мы узнали о некоторых основных концепциях и возможностях детектора жестов GestureDetector, предоставляемого флаттером, который инкапсулирует внутри множество API-интерфейсов, что позволяет нам эффективно и быстро разрабатывать приложения. Благодаря содержанию статьи мы знаем, как отслеживать такие события, как щелчок/двойной щелчок/перетаскивание, и обрабатывать логику взаимодействия с пользователем. Конечно, в модели сенсорного взаимодействия неизбежно будет конкуренция событий и конфликт событий. В этой статье мы не будем объяснять это из-за проблем с пространством. В следующей статье мы сосредоточимся на конкуренции событий и конфликте в флаттере.

автор


xiaosongzeem