手势监听和触摸事件处理

手势监听和触摸事件处理

Flutter 中如何为一个 Widget 添加点击监听器?

在 Android 中,你可以通过调用 setOnClickListener 方法在按钮这样的 View 上添加点击监听器。

在 Flutter 中有两种添加触摸监听器的方法:

  • 如果 Widget 支持事件监听,那么向它传入一个方法并在方法中处理事件。例如,RaisedButton 有一个 onPressed 参数:
@override
Widget build(BuildContext context) {
  return RaisedButton(
      onPressed: () {
        print("click");
      },
      child: Text("Button"));
}
  • 如果 Widget 不支持事件监听,将 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 可以监听非常多的手势,例如:

  • Tap

    • onTapDown - 一个可能产生点击事件的指针触摸到屏幕的特定位置。

    • onTapUp - 一个产生了点击事件的指针停止触摸屏幕的特定位置。

    • onTap - 一个点击事件已经发生。

    • onTapCancel - 之前触发了 onTapDown 事件的指针不会产生点击事件。

  • Double tap

    • onDoubleTap - 用户在屏幕同一位置连续快速地点击两次。
    • Long press

    • onLongPress - 指针在屏幕的同一位置保持了一段较长时间的触摸状态。

    • Vertical drag

    • onVerticalDragStart - 指针已经触摸屏幕并可能开始垂直移动。

    • onVerticalDragUpdate - 触摸屏幕的指针在垂直方向移动了更多的距离。

    • onVerticalDragEnd - 之前和屏幕接触并垂直移动的指针不再继续和屏幕接触,并且在和屏幕停止接触的时候以一定的速度移动。

  • Horizontal drag

    • onHorizontalDragStart - 指针已经触摸屏幕并可能开始水平移动。

    • onHorizontalDragUpdate - 触摸屏幕的指针在水平方向移动了更多的距离。

    • onHorizontalDragEnd - 之前和屏幕接触并水平移动的指针不再继续和屏幕接触,并且在和屏幕停止接触的时候以一定的速度移动。

下面的例子展示了一个实现了双击旋转 Flutter 标志的 GestureDetector:

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