40 Flutter Gesture手势处理
Flutter Gesture手势处理
1.简介
GestureDetector在Flutter中负责处理跟用户的简单手势交互,GestureDetector控件没有图像展示,只是检测用户输入的手势,并作出相应的处理,包括点击、拖动和缩放。许多控件使用GestureDetector为其他控件提供回调,比如IconButton、RaisedButton和FloatingActionButton控件有onPressed回调,当用户点击控件时触发回调,当用户点击控件时触发回调。
我们来一起看下GestureDetector的构造方法:
2.属性
GestureDetector({
Key? key,
this.child,
this.onTapDown, //单击 down
this.onTapUp, //单击 up
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, //drag–拖拽事件
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,
})
3.属性分类介绍
属性介绍
GestureWidget除key以外有39个属性,但大部分是成组出现的。大致分为以下几组:child、tap、longPress、drag、forcePress、pan、scale、behavior以及excludeFromSemantics,下边列出了其中比较常用的几个。
tap–点击事件
不同于Android中通过View.SetOnClickListener()来给组件添加点击事件,Flutter中绝大多数的组件是不能响应点击事件的。通常做法是在目标Widget外层包裹一个GestureDetector,这也就是child属性的作用,GestureDetector的大小等于子Widget的大小,也就是触控区域的大小。
onTap() :发生点击。
onDoubleTap():双击。
onTapCancel():手指离开屏幕时,触控位置不在GestureDetector范围内。
onTapDown(TapXXXDetails) :手指落在触控范围内时的回调,details参数中包含触控点的全局位置(相对于屏幕左上角)和本地位置(相对于触控区左上角)。
onTapUp(TapXXXDetails):同上。
longPress–长按事件
onLongPress() :手指在触控区停留一段时间,检测出长按(不用放手)。
onLongPressStart(LongPressXXXDetails):同上,获得检测到长按时的触控点坐标(Global和Local)。
onLongPressMoveUpdate(LongPressXXXDetails):检测到长按,手指在屏幕内(而非仅仅在触控区域内),得到触控点坐标。
onLongPressUp() :检测到长按,手指离开屏幕时。
onLongPressEnd(LongPressXXXDetails):同上,获得该点坐标。
drag–拖拽事件
onVerticalDragDown(DragDownDetails) :实际上不用拖拽,当手指接触触控区,就会产生该回调,获得该点坐标。
onVerticalDragStart(DragStartDetails):开始拖拽,details不仅包含该点坐标,而且记录了开始拖拽的时间戳。
onVerticalDragUpdate(DragUpdateDetails):纵向拖拽过程中,参数不仅包含该点坐标,且记录了当前时间戳。可以与startDrag的时间戳联合使用。
onVerticalDragEnd(DragEndDetails) :产生纵向拖拽,手指离开屏幕,获得该点坐标。
onVerticalDragCancel():点击了触控区但没有产生拖拽,或者横向拖拽至触控区外。
Horizontal横向,略。
forcePress–压感检测
哇咔咔,GestureDetector这么厉害,居然支持压力检测。
这里的压力是没有单位的,默认范围是startPressure0.0-peakPressure1.0代表从没有压力到最大压力。
onForcePressStart(ForcePressDetails) :触碰屏幕且有一定压力,压力值大于startPressure,获得压力值和触控点坐标。
onForcePressPeak(ForcePressDetails):触屏屏幕的压力大于peakPreasure,获得压力值和触控点坐标。
onForcePressUpdate(ForcePressDetails):已经被检测到产生压力的情况下,在屏幕上滑动,或者在原地改变压力大小,亦或是两者都有。同时获得压力值和触控点坐标。
onForcePressEnd(ForcePressDetails) :已检测到产生压力的情况下,手指离开屏幕。
然而,在所有的压力检测回调中都有这样一则注释:
/// Note that this callback will only be fired on
final GestureForcePressEndCallback onForcePressEnd;
也就是说,只有在具有压感屏的设备上,这些API才起作用。
pan-综合横向与纵向拖拽的拖拽事件 ————————类似于Android 中onTouch
onPanDown(DragDownDetails) :手指与屏幕接触时,获得该点坐标。 down
onPanStart(DragStartDetails):手指开始在屏幕上移动。 down
onPanCancel():
取消拖拽,暂未回调到该方法。
onPanEnd(DragEndDetails) :产生拖拽,手指离开屏幕,获得该点坐标。
onPanUpdate(DragUpdateDetails):在出发onPanDown的前提下,手指在屏幕上滑动,获得触控点坐标。
——————onPanUpdate,记录移动的过程
4.使用
1 widget 添加单击事件
Widget buildOnTab() {
return Padding(
padding: EdgeInsets.all(10),
child: GestureDetector(
onTap: () {
print("");
},
child: Container(
alignment: Alignment(0, 0),
color: Colors.grey,
height: 28,
width: 120,
child: Text(""),
),
),
);
}
2 widget 添加长按事件
Widget buildLongTab() {
return Padding(
padding: EdgeInsets.all(10),
child: GestureDetector(
onLongPress: () {
print("长按事件 ");
},
child: Container(
alignment: Alignment(0, 0),
color: Colors.grey,
height: 28,
width: 120,
child: Text("长按事件"),
),
),
);
}
3 widget 添加双击事件
Widget buildDoTab() {
return Padding(
padding: EdgeInsets.all(10),
child: GestureDetector(
onDoubleTap: () {
print("双击事件 ");
},
child: Container(
alignment: Alignment(0, 0),
color: Colors.grey,
height: 28,
width: 120,
child: Text("双击事件"),
),
),
);
}
4 widget 添加按下与抬起监听事件
Widget buildDownUp() {
return Padding(
padding: EdgeInsets.all(10),
child: GestureDetector(
onTapDown: (tapDown) {
print("按下 ");
},
onTapUp: (tapUp) {
print("抬起 ");
},
child: Container(
alignment: Alignment(0, 0),
color: Colors.grey,
height: 28,
width: 120,
child: Text("监听按下与放开"),
),
),
);
}
5.移动监听,实现Android中onTouchEvent的功能
onPanDown: (details) {
print("onPanDown:" + details.globalPosition.toString());
},
onPanUpdate: (details) {
print("onPanUpdate:" + details.globalPosition.toString());
},
5.使用inWell实现添加事件监听
使用 InkWell 同样可以实现 GestureDetector的添加事件监听功能,两者的区别是GestureDetector的child 点击无水波纹效果,而 InkWell 的child 触发事件时会有水波纹效果。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("flutter demo")), body: InWellDemo()));
}
}
class InWellDemo extends StatefulWidget {
InWellDemo({Key key}) : super(key: key);
@override
_InWellDemoState createState() {
return _InWellDemoState();
}
}
class _InWellDemoState extends State<InWellDemo> {
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Padding(
padding: EdgeInsets.all(10),
child: InkWell(
onTap: () {
print("InkWell单击事件 ");
},
highlightColor: Colors.yellow, //长按时,高亮颜色
splashColor: Colors.green, //单击时,颜色
child: Container(
alignment: Alignment(0, 0),
color: Colors.white54,
height: 50,
width: 200,
child: Text("InkWell单击事件"),
),
),
);
}
}
6.代码示例
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(home: new MyApp()));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Gestures"),
),
body: new Center(
child: new GestureDetector(
child: Padding(
padding: EdgeInsets.all(10),
child: GestureDetector(
onTap: () {
print("单击事件 ");
},
child: Container(
alignment: Alignment(0, 0),
color: Colors.grey,
height: 50,
width: 120,
child: Text("单击事件"),
),
),
),
onTap: () {
print("------onTap");
},
onTapDown: (tapDown) {
print("按下 ");
},
onTapUp: (tapUp) {
print("------onTap");
},
onDoubleTap: () {
print("------onDoubleTap");
},
onLongPress: () {
print("-----onLongPress");
},
onVerticalDragStart: (details) {
print("在垂直方向开始位置:" + details.globalPosition.toString());
},
onVerticalDragDown: (details) {
print("在垂直向下压的位置" + details.globalPosition.toString());
},
onVerticalDragEnd: (details) {
print("在垂直方向结束位置:" + details.primaryVelocity.toString());
},
onPanDown: (details) {
print("onPanDown:" + details.globalPosition.toString());
},
onPanUpdate: (details) {
print("onPanUpdate:" + details.globalPosition.toString());
},
)),
);
}
}