flutter-常用手势与阻止事件冒泡与响应
前言
在 flutter
中,除了使用 TextButton 之外,使用最多的就是GestureDetector
手势了,这篇文章就简单介绍下GestureDetector
手势
下面是手势中常常配合使用的两个方法
//获取屏幕的size信息
MediaQuery.of(context).size
//获取当前组件size信息,组件默认持有,不必从build中传递
context.size
获取当前组件的偏移量,可以通过组件的context
获取RenderBox
,可以用来动态获取更多必要的计算信息
组件渲染完成之后,可以通过组价你的context参数,间接获取组件的偏移量
RenderBox box = context.findRenderObject() as RenderBox;
final local = box.localToGlobal(Offset.zero);
print(local);
GestureDetector
手势生效范围
,默认为包裹子视图
范围内(注意:子视图一般默认会填充,再加上居中效果容易误认为点击区间出问题),且默认点击事件默认阻止向下继续冒泡
GestureDetector(
onTap: () {
//默认的点击事件,和textbutton类似,一般使用这个,抬起时生效
},
onTapDown: (TapDownDetails details) {
//点击后立即触发,特殊场景使用,一般配合tap的其他来设置点击效果
//TapDownDetails中有点击的位置等信息
},
onTapCancel: () {
//用于点击事件的取消操作,一般用于配合上面你的方法定制点击事件
},
onLongPress: () {
//长按触发事件,一般用于预览界面不适合添加额外按钮,增加长按手势触发躺床才做
},
onDoubleTap: () {
//双击触发事件,由短暂的连续单机事件封装而成,一般用于web端操作,移动端少有
},
onVerticalDragUpdate: (DragUpdateDetails details) {
//拖拽更新,pan实际走的也是这个,不信看看参数😂
//世界坐标details.globalPosition
//本地坐标details.localPosition
onUpdate(details.localPosition.dy);
},
onVerticalDragDown: (DragDownDetails details) {
//拖拽动作点击时触发一次,如果点击时需要更新位置等信息,可以调用
},
onVerticalDragStart: (DragStartDetails details) {
//拖拽动作开始时触发,实际上和down方法选择一个即可
},
onVerticalDragEnd: (DragEndDetails details) {
//拖拽结束,可以处理相关事件的结尾工作,或者恢复
},
//他们三个也是和拖拽逻辑一模一样,只不过换一个名字,参数类型都一样
//应该是对不同端的开发习惯的支持
onPanDown: (DragDownDetails details) {},
onPanEnd: (DragEndDetails details) {},
onVerticalDragStart: (DragStartDetails details) {},
onPanUpdate: (DragUpdateDetails details) {},
child: Container(
color: Colors.black26,
width: 20,
child: const Text("点击吧"),
),
),
阻止事件冒泡与响应
一般情况下,按照其他端使用手势GestureDetector
的onTap
、onTapDown
等是默认阻止向上冒泡
的,即:只会响应最上面一层视图的事件,然后事件就结束了,下面被挡住的就不会响应,如果也需要同时响应的话(可以直接调用其方法即可,这种比较少)
如果点击了某个视图,又想忽略内部的点击响应事件
,以避免其影响到到父视图或祖父等视图
的点击,可以使用 IgnorePointer
来包裹相应模块即可(且参数 ignoring 可以控制是否忽略生效,默认生效)
//阻止被包裹的点击事件响应,以便于父级或者更高级别上视图响应
const IgnorePointer(
child: GestureDetector(child: const Text('点击我,底部被挡住的就会有反应了,但我的就没反应了')),
),
场景模拟:一个ListView.builder
,item
中有一个按钮
,点击后有响应,这个场景不需要他响应,但其为三方组件,自己改不了,因此需要阻止事件的响应
,那样里面的按钮使用 IgnorePointer
包裹即可
例如:
下面的就会出现手势冲突,可以使用 IgnorePointer
包裹里面的 GestureDetector
(实际上拖拽等手势,也可能会出现不同层级的响应冲突问题),其会忽略掉被包裹的手势,阻止其向上传递冒泡
//默认响应案例
//这样点击文字就会响应顶部事件了,即:这里打印顶部+索引
ListView.builder(
itemCount: 20,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTapDown: (TapDownDetails details) {
print("底部$index");
},
child: Container(
height: 80,
color: Colors.yellow,
alignment: Alignment.center,
child: GestureDetector(
onTapDown: (TapDownDetails details) {
print("顶部$index");
},
child: Text("哈哈哈$index"),
),
)
);
},
);
//阻止顶部按钮响应的解决方案,IgnorePointer,且参数 ignoring 可以控制是否有效
//这样点击文字就会响应 底部事件了,即:这里打印底部+索引
ListView.builder(
itemCount: 20,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTapDown: (TapDownDetails details) {
print("底部$index");
},
child: Container(
height: 80,
color: Colors.yellow,
alignment: Alignment.center,
child: IgnorePointer(
child: GestureDetector(
onTapDown: (TapDownDetails details) {
print("顶部$index");
},
child: Text("哈哈哈$index"),
),
),
),
);
},
);
最后
可以点赞收藏,以后用到的时候,可以打开观看一下😂
转载自:https://juejin.cn/post/7084640719129804807