Flutter 事件与通知
Flutter中的触摸事件可分为两层来看待。第一层是触摸原事件(指针),有相应的四种事件类型:PointerDownEvent:用户与屏幕接触产生了联系。PointerMoveEvent:手指已从屏幕上的一个位置移动到另一个位置。PointerUpEvent:用户已停止接触屏幕。PointerCancelEvent:此指针的输入不再指向此应用程序。第二层就是检测到的手势,主要分为三大类,包括轻击、拖动和缩放
GestureDetector
GestureDetector 可以进行手势检测,共有7种类型事件。比如点击一次、双击、长按、垂直滑动及水平滑动等
属性 | 类型 | 简述 |
---|---|---|
onTapDown | GestureTapDownCallback |
手指按下时触发 |
onTapUp | GestureTapUpCallback |
手指抬起时触发 |
onTap | GestureTapCallback |
单击屏幕时触发 |
onTapCancel | GestureTapCancelCallback |
没有完成Tap的动作时触发 |
onDoubleTap | GestureTapCallback |
快速双击屏幕时触发 |
onLongPress | GestureLongPressCallback |
长按屏幕时触发 |
onLongPressStart | GestureLongPressStartCallback |
监听长按事件的开始 |
onLongPressMoveUpdate | GestureLongPressMoveUpdateCallback |
长按屏幕且移动手指时触发 |
onLongPressUp | GestureLongPressUpCallback |
手指完全离开屏幕时触发 |
onLongPressEnd | GestureLongPressEndCallback |
手指开始离开屏幕时触发 |
onVerticalDragDown | GestureDragDownCallback |
手指按下并在垂直方向上移动时触发 |
onVerticalDragStart | GestureDragStartCallback |
触摸点开始在垂直方向上移动时触发(在onVerticalDragDown 之后) |
onVerticalDragUpdate | GestureDragUpdateCallback |
触摸点在垂直方向上移动时触发 |
onVerticalDragEnd | GestureDragEndCallback |
停止移动,且该拖拽操作就被认为是完成了时触发 |
onVerticalDragCancel | GestureDragCancelCallback |
突然停止拖拽时触发 |
onHorizontalDragDown | GestureDragDownCallback |
参见onVerticalDragDown ,为水平方向 |
onHorizontalDragStart | GestureDragStartCallback |
参见onVerticalDragDown ,为水平方向 |
onHorizontalDragUpdate | GestureDragUpdateCallback |
参见onVerticalDragDown ,为水平方向 |
onHorizontalDragEnd | GestureDragEndCallback |
参见onVerticalDragDown ,为水平方向 |
onHorizontalDragCancel | GestureDragCancelCallback |
参见onVerticalDragDown ,为水平方向 |
onPanDown | GestureDragDownCallback |
手指接触屏幕,并且可能开始移动时触发 |
onPanStart | GestureDragStartCallback |
触摸点开始移动时触发 |
onPanUpdate | GestureDragUpdateCallback |
触摸点不断移动时触发 |
onPanEnd | GestureDragEndCallback |
操作完成手指离开屏幕时触发 |
onPanCancel | GestureDragCancelCallback |
先前触发onPanDown 的指针未完成时触发 |
onScaleStart | GestureScaleStartCallback |
触摸屏幕开始缩放操作时触发 |
onScaleUpdate | GestureScaleUpdateCallback |
缩放过程中的监听 |
onScaleEnd | GestureScaleEndCallback |
手指离开屏幕,缩放完成时触发 |
onForcePressStart | GestureForcePressStartCallback |
触摸屏幕且有足够压力时触发(仅在具有压力检测的屏幕设备支持) |
onForcePressPeak | GestureForcePressPeakCallback |
触摸屏幕压力达到最大时触发(需设备支持) |
onForcePressUpdate | GestureForcePressUpdateCallback |
有足够的压力并在屏幕上移动时触发(需设备支持) |
onForcePressEnd | GestureForcePressEndCallback |
离开屏幕时触发(需设备支持) |
behavior | HitTestBehavior |
在命中测试期间,此手势检测器应如何表现 |
excludeFromSemantics | bool |
是否从语义树中排除这些手势。 例如,用于显示工具提示的长按手势被排除在外,因为工具提示本身直接包含在语义树中,因此具有显示该工具提示的手势将导致信息重复 |
dragStartBehavior | DragStartBehavior |
设定处理拖动开始行为的方式 |
需要注意,GestureDetector并不会监听所有的手势,只有传入的回调非空时,才会监听。所以,如果想要禁用某个手势时,可将对应的回调函数设置为null
。
另外,GestureDetector的某些事件是互斥的,不能同时存在,例如onVerticalUpdate
、onHorizontalUpdate
、onPanUpdate
这三个事件不能同时存在,onPanUpdate
和onScaleUpdate
也不能同时存在。
测试手势处理回调
GestureDetector( child: Container( width: 300.0, height: 500.0, color: Colors.amber, ), onTapDown: (_) => debugPrint("onTapDown"), onTapUp: (_) => debugPrint("onTapUp"), onTap: () => debugPrint("onTap"), onTapCancel: () => debugPrint("onTapCancel"), onDoubleTap: () => debugPrint("onDoubleTap"), onLongPress: () => debugPrint("onLongPress"), onLongPressUp: () => debugPrint("onLongPressUp"), onVerticalDragDown: (_) => debugPrint("onVerticalDragDown"), onVerticalDragStart: (_) => debugPrint("onVerticalDragStart"), onVerticalDragUpdate: (_) => debugPrint("onVerticalDragUpdate"), onVerticalDragEnd: (_) => debugPrint("onVerticalDragEnd"), onVerticalDragCancel: () => debugPrint("onVerticalDragCancel"), onHorizontalDragDown: (_) => debugPrint("onHorizontalDragDown"), onHorizontalDragStart: (_) => debugPrint("onHorizontalDragStart"), onHorizontalDragUpdate: (_) => debugPrint("onHorizontalDragUpdate"), onHorizontalDragEnd: (_) => debugPrint("onHorizontalDragEnd"), onHorizontalDragCancel: () => debugPrint("onHorizontalDragCancel"), onPanDown: (_) => debugPrint("onPanDown"), onPanStart: (_) => debugPrint("onPanStart"), onPanUpdate: (_) => debugPrint("onPanUpdate"), onPanEnd: (_) => debugPrint("onPanEnd"), onPanCancel: () => debugPrint("onPanCancel"), onScaleStart: (_) => debugPrint("onScaleStart"), onScaleUpdate: (_) => debugPrint("onScaleUpdate"), onScaleEnd: (_) => debugPrint("onScaleEnd"), )
通过手势处理实现一个拖动示例
class _HomePageState extends State<HomePage> { double _left = 0.0; double _top = 0.0; GlobalKey _gKey = GlobalKey(); double stackWidth = 0.0; double stackHeight = 0.0; @override void initState() { super.initState(); // 注册一个回调,当屏幕渲染第一帧的时候回调 WidgetsBinding.instance.addPostFrameCallback((_){ stackWidth = _gKey.currentContext.size.width; stackHeight = _gKey.currentContext.size.height; }); } @override Widget build(BuildContext context) { print("_HomePageState build ..."); return Scaffold( appBar: AppBar( title: Text("Flutter Widget"), ), body: GestureDetector( onPanUpdate: (DragUpdateDetails details){ setState(() { // 边界检查 if(_left + 200 > stackWidth){ _left = stackWidth- 200; }else if(_left < 0){ _left = 0; } else{ _left += details.delta.dx; } if(_top + 200 > stackHeight){ _top = stackHeight- 200; }else if(_top < 0){ _top = 0; }else{ _top += details.delta.dy; } }); }, child: Stack( key: _gKey, children: <Widget>[ Positioned( left: _left, top: _top, width: 200.0, height: 200.0, child: Container( color: Colors.amber, ), ) ], ), ), ); }
缩放示例
class _ScaleWidgetState extends State<ScaleWidget>{ double _width = 300.0; double _height = 200.0; @override Widget build(BuildContext context) { return Center( child: GestureDetector( child: Container( width: _width, height: _height, color: Colors.pink, ), onScaleUpdate: (e) { print(e); setState(() { // 限制缩放比例在0.7-1.2之间,超过范围则变为原大小 _width = 300* e.scale.clamp(0.7, 1.2); _height = 200*e.scale.clamp(0.7, 1.2); }); }, ) ); } }
InkWell
具有水波纹效果(或称为溅墨效果)的点击事件控件。能处理的触摸事件很少,如需处理复杂的手势事件,应使用GestureDetector。
需要注意,当InkWell
的父控件设置了背景色时,是看不到溅墨效果效果的,此时需要进行特殊处理,当使用InkWell
包裹image
时,也无法显示出溅墨效果,这时建议使用Ink.Image
控件。
// 需使用Matetial 以及 Ink控件包裹 Material( child: Ink( decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(10) ), child: InkWell( onTap: (){ print("onTap..."); }, child: Container( padding: EdgeInsets.symmetric(horizontal: 16,vertical: 6), child: Text("这是按钮",style: TextStyle(color: Colors.white),), ), ), ), )
如需取消溅墨效果,可进行如下设置
// 设置highlightColor和radius取消溅墨效果 InkWell( highlightColor: Colors.transparent, radius: 0.0, child: Text( "click me", ), onTap: () { print("onTap"); }, ),
Snackbar
它是Material Design设计中的一个轻量级消息通知控件。
属性 | 类型 | 简述 |
---|---|---|
content | Widget |
展示的内容 |
backgroundColor | Color |
背景色 |
elevation | double |
阴影高度 |
shape | ShapeBorder |
形状 |
behavior | SnackBarBehavior |
位置,SnackBarBehavior.fixed 固定在底部;SnackBarBehavior.floating 显示在底部导航栏上方 |
action | SnackBarAction |
执行的动作(相当于按钮) |
duration | Duration |
停留时间 |
animation | animation |
显示或隐藏的动画效果 |
onVisible | VoidCallback |
显示时的回调 |
Scaffold.of(context).showSnackBar(SnackBar( content: Text('这是一个 SnackBar'), backgroundColor: Colors.black26, duration: Duration(seconds: 1), behavior: SnackBarBehavior.floating, action: SnackBarAction( label: '我是按钮', onPressed: () { print('点击了按钮'); }), ));
小结:
- 显示
Snackbar
:Scaffold.of(context).showSnackBar(snackBar)
- 隐藏当前的
SnackBar
:Scaffold.of(context).hideCurrentSnackBar()
THE END