手势检测与 touch 事件处理

手势检测与 touch 事件处理

如何给 Flutter 的 widget 添加点击事件?

在 iOS 里,通过把 GestureRecognizer 绑定给 UIView 来处理点击事件。在 Flutter 中,有两种方法来添加事件监听者:

  • 如果 widget 本身支持事件检测,则直接传递处理函数给它。例如,RaisedButton 拥有一个 onPressed 参数:
@override
Widget build(BuildContext context) {
  return RaisedButton(
    onPressed: () {
      print("click");
    },
    child: Text("Button"),
  );
}
  • 如果 widget 本身不支持事件检测,那么把它封装到一个 GestureDetector 中,并给它的 onTap 参数传递一个函数:
class SampleApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: GestureDetector(
          child: FlutterLogo(
            size: 200.0,
          ),
          onTap: () {
            print("tap");
          },
        ),
      ),
    );
  }
}

如何处理 widget 的其他手势?

你可以使用 GestureDetector 来监听更多的手势,例如:

  • 单击事件

    • onTapDown —— 用户在特定区域发生点触屏幕的一个即时操作。

    • onTapUp —— 用户在特定区域发生触摸抬起的一个即时操作。

    • onTap —— 从点触屏幕之后到触摸抬起之间的单击操作。

    • onTapCancel —— 用户在之前触发了 onTapDown 时间,但未触发 tap 事件。

  • 双击事件

    • onDoubleTap —— 用户在同一位置发生快速点击屏幕两次的操作。
    • 长按事件

    • onLongPress —— 用户在同一位置长时间触摸屏幕的操作。

    • 垂直拖动事件

    • onVerticalDragStart —— 用户手指接触屏幕,并且将要进行垂直移动事件。

    • onVerticalDragUpdate —— 用户手指接触屏幕,已经开始垂直移动,且会持续进行移动。

    • onVerticalDragEnd —— 用户之前手指接触了屏幕并发生了垂直移动操作,并且停止接触前还在以一定的速率移动。

  • 水平拖动事件

    • onHorizontalDragStart —— 用户手指接触屏幕,并且将要进行水平移动事件。

    • onHorizontalDragUpdate —— 用户手指接触屏幕,已经开始水平移动,且会持续进行移动。

    • onHorizontalDragEnd —— 用户之前手指接触了屏幕并发生了水平移动操作,并且停止接触前还在以一定的速率移动。

下面的示例展示了 GestureDetector 是如何实现双击时旋转 Flutter 的 logo 的:

AnimationController controller;
CurvedAnimation curve;

@override
void initState() {
  controller = AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);
  curve = CurvedAnimation(parent: controller, curve: Curves.easeIn);
}

class SampleApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: GestureDetector(
          child: RotationTransition(
            turns: curve,
            child: FlutterLogo(
              size: 200.0,
            )),
          onDoubleTap: () {
            if (controller.isCompleted) {
              controller.reverse();
            } else {
              controller.forward();
            }
          },
        ),
      ),
    );
  }
}