作者 | 前行的乌龟 地址 | juejin.im/post/5dcea24ff265da0bd05e5236
前言
Flutter 的触摸原理和 android 一样,但是再使用上有很大区别,Flutter 比 android 好用多了,android 里我们要写个类继承目标 view 重写 onTouchEvent 方法,这样我们会多写一个类,这个类只是重新定义了触摸事件的处理方法而已,其实得不偿失,还会造成类爆炸,不方便理解的问题
Flutter 中一切都是 Widget,触摸事件也是一个 Widget:GestureDetector
,我们只要用 GestureDetector
包裹内容 Widget 就行了,不需要我们单独搞一个类出来,方便阅读,方便理解,也方便编写,是编程语言发展的趋势
GestureDetector方法大全
GestureDetector
的构造函数中有很多方法,我们用不上,只用那么常用的就行,下面的这样监听函数大家看一下就行了
class GestureDetector extends StatelessWidget {
GestureDetector({
Key key,this.child,this.onTapDown,this.onTapUp,this.onTap,this.onTapCancel,this.onDoubleTap,this.onLongPress,this.onLongPressUp,this.onLongPressDragStart,this.onLongPressDragUpdate,this.onLongPressDragUp,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.down,
})
...
}
监听单击,双击,长按
这是最常用的触摸处理了:
onTap
- 单击onDoubleTap
- 双击onLongPress
- 长按
注意:
像是
双击,长按
这样的处理不可能像
单击
那样立马就响应的,而是有 200ms 的延迟,因为要在 200ms 内判断您是不是一直按着或者又按了一下
Widget build(BuildContext context) {return RaisedButton(child: Center(child: GestureDetector(child: Container(alignment: Alignment.center,color: Colors.blue,width: 200.0,height: 100.0,child: Text(
value,style: TextStyle(color: Colors.white),
),
),onTap: () => print("点击"), //点击onDoubleTap: () => print("双击"), //双击onLongPress: () => print("长安"), //长按
),
),
);
}
获取触摸数值
上面的监听方法是用来处理一般事件的,下面的方法我们可以直接拿到数值,并且 Flutter 初步给我们整理好了,划分了数值类型onPanDown
- 用户按下时触发,数据类型:DragDownDetails.globalPosition
是触摸点相对于屏幕的坐标,看名字有 global 就知道了
onPanDown: (DragDownDetails e) {// 手指按下的位置(相对于屏幕)print("用户手指按下:${e.globalPosition}");
},
onPanUpdate
- 用户在屏幕上滑动时触发,数据类型:DragUpdateDetails.delta
其数值是用户一次触摸的偏移量,注意不是总的偏移量,是每一次的
onPanUpdate: (DragUpdateDetails e) {
//用户手指滑动时,更新偏移,重新构建print("单次偏移量:${e.delta.dx} :${e.delta.dy} ");
},
onPanEnd
- 户抬起手指时触发,数据类型:DragEndDetails.velocity.pixelsPerSecond
其数据是用户手离开时 view 残留的滑动速度(包含x、y两个轴的)
onPanEnd: (DragEndDetails e){//打印滑动结束时在x、y轴上的速度print(e.velocity.pixelsPerSecond.dx,e.velocity.pixelsPerSecond.dy);
},
onVerticalDragUpdate
- 垂直方面上手指触摸的变化值,数据类型:DragUpdateDetails
onVerticalDragUpdate: (DragUpdateDetails e){
......
},
onHorizontalDragUpdate
- 水平方面上手指触摸的变化值,数据类型:DragUpdateDetails
onHorizontalDragUpdate: (DragUpdateDetails e){
......
},
第一个例子
这里我们搞一个拖动 widget 的小 democlass TestWidgetState extends State<TestWidget> {
num top = 0.0;
num left = 0.0;@overrideWidget build(BuildContext context) {return Stack(
children: [
Positioned(
top: top,
left: left,
child: GestureDetector(
child: Container(
alignment: Alignment.center,
color: Colors.blue,
width: 100.0,
height: 100.0,
child: Text("AAAAAAAA",
style: TextStyle(color: Colors.white),
),
),
onPanUpdate: (DragUpdateDetails e) {
setState(() {
left += e.delta.dx;
top += e.delta.dy;
});
},
),
),
],
);
}
}
废话不多说,我们使用 stack 这个布局来做,利用 top,left 定位来改变 widget 的位置。
缩放
onScaleUpdate
- 数据类型:ScaleUpdateDetails
,缩放值是:details.scale.clamp
,clamp 方法中的参数是缩放范围,实测貌似不管用,不知道是不是我这的原因
onScaleUpdate: (ScaleUpdateDetails details) {
setState(() {//缩放倍数在0.8到10倍之间
_width=200*details.scale.clamp(.8, 10.0);
});
我是不知道打击缩放都是怎么做的,我自己跑了个例子,我写的这个那手感是烂的一B啊
class TestWidgetState extends State<TestWidget> {var width = 150.0;var height = 150.0;
@override
Widget build(BuildContext context) {return Center(
child: (GestureDetector(
child: Container(
alignment: Alignment.center,
color: Colors.blue,
width: width,
height: height,
child: Text("AAAAAAAA",
style: TextStyle(color: Colors.white),
),
),
onScaleUpdate: (ScaleUpdateDetails details) {
setState(() {if ((width *= details.scale.clamp(0.5, 1.5)) > 300) width = 200;if ((width *= details.scale.clamp(0.5, 1.5)) < 50) width = 100;if ((height *= details.scale.clamp(0.5, 1.5)) > 300) height = 200;if ((height *= details.scale.clamp(0.5, 1.5)) < 50) height = 100;print("scale: ${details.scale.clamp}");
});
},
)),
);
}
后来想了想手感烂应该是我没加系数进去,我试了下,加入了系数,系数=0.1,但是感觉还是没啥用...
---END---
你点的每个好看,我都认真当成了喜欢