Flutter手势组件(2):PointerEvent
一、PointerEvent介绍
PointerEvent
是触摸、手写笔、鼠标事件的基类。
在上文中,我们知道了什么是Listener
并写了一个简单的案例,在使用案例的过程中我们的事件里面都带了一个event
参数,而所有的事件最终都是继承自PointerEvent
,那我们接下来看看event
的参数有什么作用。
二、PointerEvent构造函数
const PointerEvent({
this.embedderId = 0,
this.timeStamp = Duration.zero,
this.pointer = 0,
this.kind = PointerDeviceKind.touch,
this.device = 0,
this.position = Offset.zero,
Offset? localPosition,
this.delta = Offset.zero,
Offset? localDelta,
this.buttons = 0,
this.down = false,
this.obscured = false,
this.pressure = 1.0,
this.pressureMin = 1.0,
this.pressureMax = 1.0,
this.distance = 0.0,
this.distanceMax = 0.0,
this.size = 0.0,
this.radiusMajor = 0.0,
this.radiusMinor = 0.0,
this.radiusMin = 0.0,
this.radiusMax = 0.0,
this.orientation = 0.0,
this.tilt = 0.0,
this.platformData = 0,
this.synthesized = false,
this.transform,
this.original,
}) : localPosition = localPosition ?? position,
localDelta = localDelta ?? delta;
三、PointerEvent属性和说明
PointerEvent
的属性非常多,但在我们实际的开发过程中很少会使用到,只有在特定的情景下才会使用对应的属性。
-
如需要做一个全局悬浮的按钮我们会使用到
position
-
如需要做绘图软件我们需要用到
buttons
、kind
等
所以大家可以根据实际的应用场景来使用对应的属性即可,下面是我对PointerEvent
的属性进行的一个详细描述:
字段 | 属性 | 描述 |
---|---|---|
embedderId | int | 标识平台事件ID |
timeStamp | Duration | 事件调度时间 |
pointer | int | 指针唯一标识符,每一次点击都会是一个新的,不会重复 |
kind | PointerDeviceKind | 指针事件的输入设备类型 |
device | int | 设备唯一标识符,在交互中会重复使用 |
position | Offset | 指针相对于全局坐标的偏移 |
localPosition | Offset | 指针相对于当前容器坐标的偏移 |
delta | Offset | 两次指针移动事件的距离 |
localDelta | Offset | 两次指针移动事件的距离(当前容器) |
down | bool | 设置当前指针是否按下 |
obscured | bool | 是否遮挡应用程序的窗口,该属性官方还没实现 |
distance | double | 检测物体与输入表面的距离 |
size | double | 被按下屏幕的区域大小 |
radiusMajor | double | 接触椭圆沿主轴的半径,以逻辑像素为单位 |
radiusMinor | double | 接触椭圆沿短轴的半径,以逻辑像素为单位 |
orientation | double | 检测到的物体的方向(指针移动方向),以弧度为单位 |
tilt | double | 检测到的物体的倾斜角度,以弧度为单位 |
synthesized | bool | 设置事件是否由 Flutter 合成。 |
transform | Matrix4 | 用于从全局坐标转换此事件的转换 |
original | PointerEvent | 在任何transform之前的原始未转换PointerEvent事件 |
四、behavior属性
behavior
属性,它决定子组件如何响应命中测试,它的值类型为HitTestBehavior
,这是一个枚举类,有三个枚举值
-
HitTestBehavior.deferToChild:对子组件一个接一个的进行命中测试,如果子组件中有测试通过的,则当前组件通过,这就意味着,如果指针事件作用于子组件上时,其父级组件也肯定可以收到该事件
-
HitTestBehavior.opaque:在命中测试时,将当前组件当成不透明处理(即使本身是透明的),最终的效果相当于当前Widget的整个区域都是点击区域
-
HitTestBehavior.translucent:点击组件透明区域时,可以对自身边界内及底部可视区域都进行命中测试,这意味着点击顶部组件透明区域时,顶部组件和底部组件都可以接收到事件
五、代码演示
// ignore_for_file: prefer_const_constructors
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: ListenerSimpleExample(),
);
}
}
class ListenerSimpleExample extends StatefulWidget {
const ListenerSimpleExample({super.key});
@override
State<ListenerSimpleExample> createState() => _ListenerSimpleExampleState();
}
class _ListenerSimpleExampleState extends State<ListenerSimpleExample> with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
appBar: AppBar(
title: Text("Listener"),
),
body: Center(
child: Stack(
children: [
Listener(
child: ConstrainedBox(
constraints: BoxConstraints.tight(Size(400, 200)),
child: Container(
color: Colors.greenAccent,
)
),
onPointerDown: (event) => debugPrint("绿色盒子被点击了"),
),
Listener(
onPointerDown: (event) => debugPrint("文字点击事件回调"),
behavior: HitTestBehavior.deferToChild,
// behavior: HitTestBehavior.opaque,
// behavior: HitTestBehavior.translucent,
child: ConstrainedBox(
constraints: BoxConstraints.tight(Size(400, 200)),
child: Center(child: Text("点击文字", style: TextStyle(
color: Colors.white,
fontSize: 30
),)),
),
)
],
),
),
);
}
}
效果图如下所示:
我们这里演示每次都是先点击绿色盒子在点击文字,以便大家能更好的分辨出这三个属性的使用区别。
当属性设置为HitTestBehavior.deferToChild
控制台输出结果:
flutter: 绿色盒子被点击了
flutter: 文字点击事件回调
当属性设置为HitTestBehavior.opaque
控制台输出结果:
flutter: 文字点击事件回调
flutter: 文字点击事件回调
当属性设置为HitTestBehavior.translucent
控制台输出结果:
flutter: 文字点击事件回调
flutter: 绿色盒子被点击了
flutter: 文字点击事件回调