Flutter事件监听

2023-03-19  本文已影响0人  Imkata

一. 事件监听

在大前端的开发中,必然存在各种各样和用户交互的情况:比如手指点击、手指滑动、双击、长按等等。

在Flutter中,手势有两个不同的层次:

2.1. 指针事件Pointer

Pointer 代表的是人机界面交互的原始数据。一共有四种指针事件:

Pointer的原理是什么呢?

原始指针事件使用Listener来监听:

class HomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Listener(
        child: Container(
          width: 200,
          height: 200,
          color: Colors.red,
        ),
        onPointerDown: (event) => print("手指按下:$event"),
        onPointerMove: (event) => print("手指移动:$event"),
        onPointerUp: (event) => print("手指抬起:$event"),
      ),
    );
  }
}

如果想拿到点击的位置,可以用如下方式:

// 拿到相当于屏幕坐标位置
print(event.position);
// 拿到相当于红色矩形框的坐标位置
print(event.localPosition);

2.2. 手势识别Gesture

Gesture是对一系列Pointer的封装,官方建议开发中尽可能使用Gesture,而不是Pointer。

Gesture分成非常多的种类:

点击

双击:

长按:

纵向拖拽:

横向拖拽:

移动:

从Widget的层面来监听手势,我们需要使用:GestureDetector。

class GestureDemo extends StatelessWidget {
  const GestureDemo({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Center(
      child: GestureDetector(
        onTapDown: (details) {
          print("手指按下");
          print(details.globalPosition);
          print(details.localPosition);
        },
        onTapUp: (details) {
          print("手指抬起");
        },
        onTapCancel: () {
          print("手势取消");
        },
        onTap: () {
          print("手势点击");
        },
        onDoubleTap: () {
          print("手指双击");
        },
        onLongPress: () {
          print("长按手势");
        },
        child: Container(
          width: 200,
          height: 200,
          color: Colors.orange,
        ),
      ),
    );
  }
}

2.3. 阻止冒泡

  1. 当Container里面包裹另外一个Container的时候,就算里面的Container也设置宽高,里面的Container的宽高也会撑满外面的Container。如果我们想让里面的Container有宽高,可以将外面的Container改成column,或者给外面的Container添加alignment属性

  2. 默认情况下,点击里面的Container的事件偶尔的时候会冒泡到外面,如果我们不想冒泡到外面,可以使用Stack让两个Container层叠起来,这时候我们点击里面的就会打印inner click,点击外面的就会打印outer click

  3. 如果我们想无论点击里面还是外面都打印outer click,可以使用IgnorePointer忽略里面的点击

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("列表测试"),
      ),
      body: Center(
        child: Stack(
          alignment: Alignment.center,
          children: <Widget>[
            GestureDetector(
              onTapDown: (details) {
                print("outer click");
              },
              child: Container(
                width: 200,
                height: 200,
                color: Colors.yellow,
              // 当Container里面包裹另外一个Container的时候,就算里面的Container也设置宽高,里面的Container的宽高也会撑满外面的Container
              // 如果我们想让里面的Container有宽高,可以将外面的Container改成column,或者给外面的Container添加alignment属性
                alignment: Alignment.center,
              ),
            ),
            // 默认情况下,点击里面的Container的事件偶尔的时候会冒泡到外面,如果我们不想冒泡到外面,可以使用Stack让两个Container层叠起来,这时候我们点击里面的就会打印inner click,点击外面的就会打印outer click
            // 如果我们想无论点击里面还是外面都打印outer click,可以使用IgnorePointer忽略里面的点击
            IgnorePointer(
              child: GestureDetector(
                onTapDown: (details) {
                  print("inner click");
                },
                child: Container(
                  width: 100,
                  height: 100,
                  color: Colors.red,
                ),
              ),
            )
          ],
        ),
      ),
    );
  }
}

二. 跨组件事件:EventBus

在组件之间如果有事件需要传递,一方面可以一层层来传递,另一方面我们也可以使用一个EventBus工具来完成。

其实EventBus在Vue、React中都是一种非常常见的跨组件通信的方式:

这里我们直接选择第三方的EventBus:

dependencies:
  event_bus: ^1.1.1

第一:我们需要定义一个希望在组件之间传递的对象

class UserInfo {
  String nickname;
  int level;

  UserInfo(this.nickname, this.level);
}

第二:创建一个全局的EventBus对象

final eventBus = EventBus();

第三:在某个Widget中,发出事件

class HYButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      child: Text("HYButton"),
      onPressed: () {
        final info = UserInfo("why", 18);
        eventBus.fire(info);
      },
    );
  }
}

第四:在某个Widget中,监听事件

class HYText extends StatefulWidget {
  @override
  _HYTextState createState() => _HYTextState();
}

class _HYTextState extends State<HYText> {
  String message = "Hello Coderwhy";

  @override
  void initState() {
    super.initState();

    eventBus.on<UserInfo>().listen((data) {
      setState(() {
        message = "${data.nickname}-${data.level}";
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Text(message, style: TextStyle(fontSize: 30),);
  }
}
上一篇 下一篇

猜你喜欢

热点阅读