美文网首页
Flutter 之 原始指针事件处理 (四十七)

Flutter 之 原始指针事件处理 (四十七)

作者: maskerII | 来源:发表于2022-05-03 21:08 被阅读0次

1. 命中测试简介

在移动端,各个平台或UI系统的原始指针事件模型基本都是一致,即:一次完整的事件分为三个阶段:手指按下、手指移动、和手指抬起,而更高级别的手势(如点击、双击、拖动等)都是基于这些原始事件的。

当指针按下时,Flutter会对应用程序执行命中测试(Hit Test),以确定指针与屏幕接触的位置存在哪些组件(widget), 指针按下事件(以及该指针的后续事件)然后被分发到由命中测试发现的最内部的组件,然后从那里开始,事件会在组件树中向上冒泡,这些事件会从最内部的组件被分发到组件树根的路径上的所有组件,这和Web开发中浏览器的事件冒泡机制相似, 但是Flutter中没有机制取消或停止“冒泡”过程,而浏览器的冒泡是可以停止的。注意,只有通过命中测试的组件才能触发事件

2. Listener 组件

Listener 定义

  const Listener({
    Key? key,
    this.onPointerDown, // 手指按下回调
    this.onPointerMove, // 手指移动回调
    this.onPointerUp, // 手指抬起回调
    this.onPointerHover, // 悬停
    this.onPointerCancel, // 触摸事件取消回调
    this.onPointerSignal, // 
    this.behavior = HitTestBehavior.deferToChild,
    Widget? child,
  })

示例


class MSListenerDemo1 extends StatefulWidget {
  const MSListenerDemo1({Key? key}) : super(key: key);

  @override
  State<MSListenerDemo1> createState() => _MSListenerDemo1State();
}

class _MSListenerDemo1State extends State<MSListenerDemo1> {
  PointerEvent? _event;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("ListenerDemo1")),
      body: Center(
        child: Listener(
          onPointerDown: (PointerDownEvent event) =>
              setState(() => _event = event),
          onPointerMove: (PointerMoveEvent event) =>
              setState(() => _event = event),
          onPointerUp: (PointerUpEvent event) => setState(() => _event = event),
          child: Container(
            color: Colors.amber,
            width: 200,
            height: 200,
            alignment: Alignment.center,
            child: Text("${_event?.localPosition ?? ''} "),
          ),
        ),
      ),
    );
  }
}

image.png

手指在橘黄色矩形区域内移动即可看到当前指针偏移
当触发指针事件时,对应的事件会回调,参数 PointerDownEvent、 PointerMoveEvent、 PointerUpEvent 都是PointerEvent的子类。

注意 Pointer,即“指针”, 指事件的触发者,可以是鼠标、触摸板、手指。

PointerEvent类中包括当前指针的一些信息,如:

  • position:它是指针相对于当对于全局坐标的偏移。
  • localPosition: 它是指针相对于当对于本身布局坐标的偏移。
  • delta:两次指针移动事件(PointerMoveEvent)的距离。
  • pressure:按压力度,如果手机屏幕支持压力传感器(如iPhone的3D Touch),此属性会更有意义,如果手机不支持,则始终为1。
  • orientation:指针移动方向,是一个角度值。

3. 忽略指针事件

使用IgnorePointer和AbsorbPointer来忽略指针事件

IgnorePointer和AbsorbPointer,这两个组件都能阻止子树接收指针事件,不同之处在于AbsorbPointer本身会参与命中测试,而IgnorePointer本身不会参与,这就意味着AbsorbPointer本身是可以接收指针事件的(但其子树不行),而IgnorePointer不可以

示例 IgnorePointer


class MSListenerDemo2 extends StatelessWidget {
  const MSListenerDemo2({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("ListenerDemo2")),
      body: Center(
        child: Listener(
          onPointerDown: (event) => print("out"),
          child: IgnorePointer(
            child: Listener(
              onPointerDown: (event) => print("in"),
              child: Container(
                color: Colors.amber,
                width: 200,
                height: 200,
              ),
            ),
          ),
        ),
      ),
    );
  }
}

点击Container时,无点击事件日志打印。
由于Container在IgnorePointer子树上,所以不会响应指针事件,所以日志不会输出"in",又由于IgnorePointer不会参与命中测试,因而日志不会输出"out"

示例2 AbsorbPointer


class MSListenerDemo3 extends StatelessWidget {
  const MSListenerDemo3({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("MSListenerDemo3")),
      body: Center(
        child: Listener(
          onPointerDown: (event) => print("out"),
          child: AbsorbPointer(
            child: Listener(
              onPointerDown: (event) => print("in"),
              child: Container(
                color: Colors.amber,
                width: 200,
                height: 200,
              ),
            ),
          ),
        ),
      ),
    );
  }
}

点击Container时,日志会输出"out"
由于Container在AbsorbPointer的子树上,所以不会响应指针事件,所以日志不会输出"in",但AbsorbPointer本身是可以接收指针事件的,所以会输出"out"

参考:https://book.flutterchina.club/chapter8/listener.html

相关文章

  • Flutter 之 原始指针事件处理 (四十七)

    1. 命中测试简介 在移动端,各个平台或UI系统的原始指针事件模型基本都是一致,即:一次完整的事件分为三个阶段:手...

  • Flutter 小技巧——手势处理

    Flutter手势处理 在Flutter中的手势事件分为两层。第一层有原始指针事件,它描述了屏幕上指针(例如,触摸...

  • Flutter_点击事件和手势

    Flutter_点击事件和手势 Flutter中的手势系统有两个独立的层。第一层具有原始指针事件,其描述屏幕上指针...

  • Flutter笔记八之事件监听

    Flutter把事件监听分成两个部分,分别是原始指针事件(Pointer Events)和手势识别(Gesture...

  • flutter用户交互事件处理

    在移动端所谓的用户交互事件既是用户的手势操作处理。手势操作在flutter中可分为两类: 第一类是原始的指针事件(...

  • Flutter开发 -- [15 - 事件监听]

    一. 事件监听 在Flutter中,手势有两个不同的层次: 第一层:原始指针事件(Pointer Events):...

  • Flutter 用户交互事件

    前言 在 Flutter 中手势操作分为两类: 原始的指针事件(Pointer Event),即原生开发中常见的触...

  • 7 手势、自定义Widget

    手势 Flutter中的手势系统有两个独立的层。第一层为原始指针(pointer)事件,它描述了屏幕上指针(例如,...

  • Day12 - Flutter - 事件监听

    概述 事件监听 跨组件事件 一、事件监听 1.1、在Flutter中,手势的两个不同的层次第一层:原始指针事件(P...

  • 用户交互事件该如何响应?

    手势操作在 Flutter 中分为两类: - 第一类是原始的指针事件(Pointer Event),即原生开发中常...

网友评论

      本文标题:Flutter 之 原始指针事件处理 (四十七)

      本文链接:https://www.haomeiwen.com/subject/moyiyrtx.html