1 指针事件 Pointer

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

  • PointerDownEvent 指针在特定位置与屏幕接触
  • PointerMoveEvent 指针从屏幕的一个位置移动到另外一个位置
  • PointerUpEvent 指针与屏幕停止接触
  • PointerCancelEvent 指针因为一些特殊情况被取消

Pointer的原理是什么呢?

  • 在指针落下时,框架做了一个 hit test 的操作,确定与屏幕发生接触的位置上有哪些Widget以及分发给最内部的组件去响应;
  • 事件会沿着最内部的组件向组件树的根冒泡分发;
  • 不存在用于取消或者停止指针事件进一步分发的机制;

    1. class HomeContent extends StatelessWidget {
    2. const HomeContent({Key? key}) : super(key: key);
    3. @override
    4. Widget build(BuildContext context) {
    5. return Center(
    6. child: Listener(
    7. child: Container(
    8. width: 200,
    9. height: 200,
    10. color: Colors.red,
    11. ),
    12. onPointerDown: (event) {
    13. print("手指按下:$event");
    14. print(event.position); // 用于获取相对于屏幕的位置信息
    15. print(event.localPosition); // 获取相对于当前Widget的位置信息
    16. },
    17. onPointerMove: (event) => print("手指移动:$event"),
    18. onPointerUp: (event) => print("手指抬起:$event"),
    19. ),
    20. );
    21. }
    22. }

    2 手势识别 Gesture

    Gesture是对一系列Pointer的封装,官方建议开发中尽可能使用Gesture,而不是Pointer
    从Widget的层面来监听手势,我们需要使用:GestureDetector

  • 点击:

    • onTapDown:用户发生手指按下的操作
    • onTapUp:用户发生手指抬起的操作
    • onTap:用户点击事件完成
    • onTapCancel:事件按下过程中被取消
  • 双击:
    • onDoubleTap:快速点击了两次
  • 长按:
    • onLongPress:在屏幕上保持了一段时间
  • 纵向拖拽:
    • onVerticalDragStart:指针和屏幕产生接触并可能开始纵向移动;
    • onVerticalDragUpdate:指针和屏幕产生接触,在纵向上发生移动并保持移动;
    • onVerticalDragEnd:指针和屏幕产生接触结束;
  • 横线拖拽:
    • onHorizontalDragStart:指针和屏幕产生接触并可能开始横向移动;
    • onHorizontalDragUpdate:指针和屏幕产生接触,在横向上发生移动并保持移动;
    • onHorizontalDragEnd:指针和屏幕产生接触结束;
  • 移动:

    • onPanStart:指针和屏幕产生接触并可能开始横向移动或者纵向移动。如果设置了 onHorizontalDragStart 或者 onVerticalDragStart,该回调方法会引发崩溃;
    • onPanUpdate:指针和屏幕产生接触,在横向或者纵向上发生移动并保持移动。如果设置了 onHorizontalDragUpdate 或者 onVerticalDragUpdate,该回调方法会引发崩溃。
    • onPanEnd:指针先前和屏幕产生了接触,并且以特定速度移动,此后不再在屏幕接触上发生移动。如果设置了 onHorizontalDragEnd 或者 onVerticalDragEnd,该回调方法会引发崩溃。 ```dart class HomeContent extends StatelessWidget { const HomeContent({Key? key}) : super(key: key);

    @override Widget build(BuildContext context) { return Center(

    1. child: GestureDetector(
    2. child: Container(
    3. width: 200,
    4. height: 200,
    5. color: Colors.red,
    6. ),
    7. onTap: () {
    8. print("tap");
    9. },
    10. onTapDown: (detail) {
    11. print(detail.globalPosition);
    12. print(detail.localPosition);
    13. },
    14. onTapUp: (detail) {
    15. print(detail.globalPosition);
    16. print(detail.localPosition);
    17. }
    18. ),

    ); } } ```

    3 跨组件事件 EventBus

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

EventBus相当于是一种订阅者模式,通过一个全局的对象来管理;
这个EventBus我们可以自己实现,也可以使用第三方的EventBus;
这里我们直接选择第三方的EventBus:

  1. dependencies:
  2. event_bus:^1.1.1
  1. class HomeContent extends StatelessWidget {
  2. const HomeContent({Key? key}) : super(key: key);
  3. @override
  4. Widget build(BuildContext context) {
  5. return Center(
  6. child: Row(
  7. children: [
  8. MyText(),
  9. MyButton()
  10. ]
  11. ),
  12. );
  13. }
  14. }
  15. class UserInfo {
  16. String nickname;
  17. int level;
  18. UserInfo(this.nickname, this.level);
  19. }
  20. final eventBus = EventBus();
  21. class MyButton extends StatelessWidget {
  22. @override
  23. Widget build(BuildContext context) {
  24. return ElevatedButton(
  25. child: Text("MyButton"),
  26. onPressed: () {
  27. final info = UserInfo("ws", 18);
  28. eventBus.fire(info);
  29. },
  30. );
  31. }
  32. }
  33. class MyText extends StatefulWidget {
  34. const MyText({ Key? key }) : super(key: key);
  35. @override
  36. State<MyText> createState() => _MyTextState();
  37. }
  38. class _MyTextState extends State<MyText> {
  39. String message = "Hello ws";
  40. @override
  41. void initState() {
  42. super.initState();
  43. eventBus.on<UserInfo>().listen((data) {
  44. setState(() {
  45. message = "${data.nickname}-${data.level}";
  46. });
  47. });
  48. }
  49. @override
  50. Widget build(BuildContext context) {
  51. return Text(message, style: TextStyle(fontSize: 30),);;
  52. }
  53. }