GestureDetector:是手势识别的组件,可以识别点击、双击、长按事件、拖动、缩放等手势
GestureDetector({
Key key,
this.child,
this.onTapDown,//按下时回调
this.onTapUp,//抬起时回调
this.onTap,//点击事件回调
this.onTapCancel,//点击取消事件回调
this.onSecondaryTap,
this.onSecondaryTapDown,
this.onSecondaryTapUp,
this.onSecondaryTapCancel,
this.onTertiaryTapDown,
this.onTertiaryTapUp,
this.onTertiaryTapCancel,
this.onDoubleTapDown,//短时间内双击按下时回调
this.onDoubleTap,//短时间内双击回调
this.onDoubleTapCancel,//短时间内双击取消事件回调
this.onLongPress,//长按事件回调
this.onLongPressStart,//长按开始事件回调
this.onLongPressMoveUpdate,//长按移动事件回调
this.onLongPressUp,//长按抬起事件回调
this.onLongPressEnd,//长按结束事件回调
this.onSecondaryLongPress,
this.onSecondaryLongPressStart,
this.onSecondaryLongPressMoveUpdate,
this.onSecondaryLongPressUp,
this.onSecondaryLongPressEnd,
this.onVerticalDragDown,//垂直滑动按下事件回调
this.onVerticalDragStart,//垂直滑动开始事件回调
this.onVerticalDragUpdate,//垂直滑动更新事件回调
this.onVerticalDragEnd,//垂直滑动结束事件回调
this.onVerticalDragCancel,//垂直滑动取消事件回调
this.onHorizontalDragDown,//水平滑动按下事件回调
this.onHorizontalDragStart,///水平滑动开始事件回调
this.onHorizontalDragUpdate,//水平滑动更新事件回调
this.onHorizontalDragEnd,//水平滑动结束事件回调
this.onHorizontalDragCancel,//水平滑动取消事件回调
this.onForcePressStart,//回调函数只会在有压力的设备上被触发
this.onForcePressPeak,
this.onForcePressUpdate,
this.onForcePressEnd,
this.onPanDown,//按压时回调
this.onPanStart,//按压拖动开始回调
this.onPanUpdate,//按压拖动回调
this.onPanEnd,//按压拖动结束回调
this.onPanCancel,//按压拖动取消回调
this.onScaleStart,//缩放开始事件回调
this.onScaleUpdate,//缩放更新事件回调
this.onScaleEnd,//缩放结束事件回调
this.behavior,//手势检测器在触摸中应该如何工作
this.excludeFromSemantics = false,
this.dragStartBehavior = DragStartBehavior.start,
}) : assert(excludeFromSemantics != null),
assert(dragStartBehavior != null),
assert(() {
final bool haveVerticalDrag = onVerticalDragStart != null || onVerticalDragUpdate != null || onVerticalDragEnd != null;
final bool haveHorizontalDrag = onHorizontalDragStart != null || onHorizontalDragUpdate != null || onHorizontalDragEnd != null;
final bool havePan = onPanStart != null || onPanUpdate != null || onPanEnd != null;
final bool haveScale = onScaleStart != null || onScaleUpdate != null || onScaleEnd != null;
if (havePan || haveScale) {
if (havePan && haveScale) {
throw FlutterError.fromParts([
ErrorSummary('Incorrect GestureDetector arguments.'),
ErrorDescription(
'Having both a pan gesture recognizer and a scale gesture recognizer is redundant; scale is a superset of pan.'
),
ErrorHint('Just use the scale gesture recognizer.')
]);
}
final String recognizer = havePan ? 'pan' : 'scale';
if (haveVerticalDrag && haveHorizontalDrag) {
throw FlutterError(
'Incorrect GestureDetector arguments.\n'
'Simultaneously having a vertical drag gesture recognizer, a horizontal drag gesture recognizer, and a $recognizer gesture recognizer '
'will result in the $recognizer gesture recognizer being ignored, since the other two will catch all drags.'
);
}
}
return true;
}()),
super(key: key);
onTapDown 按下时回调
onTapUp 抬起时回调
onTap 点击事件回调
onTapCancel 点击取消事件回调
onDoubleTapDown 短时间内双击按下时回调
onDoubleTap 短时间内双击回调
onDoubleTapCancel 短时间内双击取消事件回调
onLongPress 长按事件回调
onLongPressStart 长按开始事件回调
onLongPressMoveUpdate 长按移动事件回调
onLongPressUp 长按抬起事件回调
onLongPressEnd 长按结束事件回调
onVerticalDragDown 垂直滑动按下事件回调
onVerticalDragStart 垂直滑动开始事件回调
onVerticalDragUpdate 垂直滑动更新事件回调
onVerticalDragEnd 垂直滑动结束事件回调
onVerticalDragCancel 垂直滑动取消事件回调
onHorizontalDragDown 水平滑动按下事件回调
onHorizontalDragStart 水平滑动开始事件回调
onHorizontalDragUpdate 水平滑动更新事件回调
onHorizontalDragEnd 水平滑动结束事件回调
onHorizontalDragCancel 水平滑动取消事件回调
onPanDown 按压时回调(我自己理解为点击事件,但是比onTap优先级高,onPan先执行先取消,onPan比onTap多个滑动监听)
onPanStart 按压拖动开始回调,按压开始,不能与 onScale ,onVerticalDrag,onHorizontalDrag,同时使用 onPanUpdate 按压拖动回调 onPanEnd 按压拖动结束回调
onPanCancel 按压拖动取消回调
onScaleStart 缩放开始事件回调缩放开始,不能与 onPan ,onVerticalDrag,onHorizontalDrag,同时使用
onScaleUpdate 缩放更新事件回调
onScaleEnd 缩放结束事件回调
behavior 手势检测器在触摸中应该如何工作
HitTestBehavior.deferToChild:只有当前容器中的child被点击时才会响应点击事件
HitTestBehavior.opaque:点击整个区域都会响应点击事件,但是点击事件不可穿透向下传递,注释翻译:阻止视觉上位于其后方的目标接收事件。
HitTestBehavior.translucent:同样是点击整个区域都会响应点击事件,和opaque的区别是点击事件是否可以向下传递,注释翻译:半透明目标既可以在其范围内接受事件,也可以允许视觉上位于其后方的目标接收事件
4.1、点击屏幕:onPanDown--onPanCancel--onTapDown--onTapUp--onTap
4.2、点击滑动:onPanDown--onTapDown--onTapCancel--onPanStart--onPanUpdate--onPanEnd
4.3、双击屏幕:onPanDown--onPanCancel--onDoubleTapDown--onPanDown--onPanCancel--onDoubleTap
4.4、长按屏幕:onPanDown--onTapDown--onTapCancel--onPanCancel--onLongPressStart--onLongPress--onLongPressMoveUpdate--onLongPressEnd--onLongPressUp
4.5、手指左右滑动:onVerticalDragDown--onHorizontalDragDown--onVerticalDragCancel--onHorizontalDragStart--onHorizontalDragUpdate--onHorizontalDragEnd
4.6、手指上下滑动:onVerticalDragDown--onHorizontalDragDown--onHorizontalDragCancel--onVerticalDragStart--onVerticalDragUpdate--onVerticalDragEnd
4.7、缩放:onScaleStart--onScaleUpdate--onScaleEnd
5.1、给组件添加按键监听
class _GestureDetectorFulState extends State {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("GestureDetector学习"),
),
body: Center(
child: GestureDetector(
//一定要加(按钮和文字之间的空白,也添加监听了)
behavior: HitTestBehavior.opaque,
onPanDown: (value) {
print("我是onPanDown");
},
child: Row(
children: [
OutlinedButton(
child: Text("按钮"),
onPressed: () {
print("点击了button");
},
),
SizedBox(width: 80),
Text("文字")
],
)
),
)
));
}
}
Flutter--GestureDetector手势识别组件 - 简书一、GestureDetector 的介绍 GestureDetector:是手势识别的组件,可以识别点击、双击、长按事件、拖动、缩放等手势 二、GestureDetecto...https://www.jianshu.com/p/c338c7975f30
在GestureDetector中有两个重要属性值globalPosition和localPosition,两者都是Offset对象。
globalPosition就像它的命名表示当前手势触点在**全局坐标系位置
与对应组件顶点坐标的偏移量(dx,dy)
;
localPosition则就表示当前手势触点在对应组件坐标系位置
与对应组件顶点坐标的偏移量(dx,dy)
**。
例如如下代码中,为Container设置了GestureDetector手势监听,在update回调中获取updateDetail对象,在Text中显示globalPosition偏移量。从中获取到的globalPosition和localPosition中dx的值相同,dy却不同。也就是因为Scaffold中设置了AppBar,相对于body他的全局坐标系并非它自身。但若将Scaffold中的AppBar去除,让body撑满整个Scaffold,那么在手势监听中获取到的globalPosition和localPosition偏移量将相同。
需要注意的是对于globalPosition在安卓中还包含了手机状态栏的高度。
DragUpdateDetails 相当网页前端的Evnet事件,可以获取当前触摸点的全局坐标和局部坐标。
onPanUpdate: (DragUpdateDetails detail) {
//获取当前触摸点的全局坐标
var globalPosition=detail.globalPosition;
//获取当前触摸点的局部坐标
var localPosition=detail.localPosition;
}
当前的页面结构(PainterPage):
Scafford
body
onPanUpdate:(detail){
final RenderBox Box = context.findRenderObject(); // 获取的对象为当前页面对象,PainterPage
Offset localPosition = Box.globalToLocal(detail.globalPosition); // 转换为局部坐标但实际是全局坐标
Offset globalPosition = Box.localToGlobal(detail.globalPosition); // 获得的是全局坐标。
}
为甚么通过这样的方式,不能正确获取到局部坐标呢?
原因在于context.findRenderObject()
,通过context
,获取到的Box,实际上是PaintPage本身。所以,对于Box自身来说全局坐标
和局部坐标
是一致的。
而实际上我们真正想要的是GestureDetector里的坐标系。由前面我们可以知道context.findRenderObject()
只能获取context
当前所在页面的页面 Widget
。
为了解决不能获取到GuesterDetector
的坐标的问题,我们需要将GuesterDetector
封装成一个StatefulWidget或者一个StatelessWidget,即GuesterDetectorWidget
。再将GuesterDetectorWidget
引入到PainterPage
。
更详细的说明可以参详字母索引快速定位
onPanUpdate:(detail){
final RenderBox Box = context.findRenderObject(); // 获取的对象为当前页面对象,PainterPage
Offset localPosition = Box.globalToLocal(detail.globalPosition); // 转换为局部坐标
Offset globalPosition = Box.localToGlobal(detail.globalPosition); // 获得的是全局坐标。
}
MaterialApp(
theme: AppTheme.themes[store.state.appThemeState.themeType],
home: Scaffold(
appBar: AppBar(),
body: GestureDetector(
onPanStart: (detail) {
showLog(detail.runtimeType, detail.localPosition,
detail.globalPosition);
},
onPanUpdate: (detail) {
showLog(detail.runtimeType, detail.localPosition,
detail.globalPosition);
setState(() {
offsetText = "globalPosition: ${Offset(detail.globalPosition.dx, detail.globalPosition.dy).toString()} \n"
"localPosition: ${Offset(detail.localPosition.dx, detail.localPosition.dy).toString()}";
});
},
onPanEnd: (detail) {
setState(() {
offsetText = "end";
});
},
child: Container(
color: Colors.red,
width: double.infinity,
height: double.infinity,
child: Center(
child: Text(
offsetText,
style: TextStyle(
color: Colors.white,
fontSize: 25,
),
),
),
),
),
),
);
可以看到当Scaffold包含和未包含AppBar时,Container两个偏移量输出的差异
#### 知识地图
Flutter的坐标体系是以Widget的左上角为原点,向左为正x轴,以下为正y轴;
全局坐标是整个屏幕的左上角开始计算的
局部坐标,是以当前GestureDetector包裹的Wiget的左上角为原点开始计算的
参考资料:
Flutter实战之手势操作篇
实现 View 的移动拖拽
flutter 白板工具
我们通过for循环建立的控件的时候,通过点击判断索引值跳转到不同页面