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
    








暂无评论内容