如需转载,请注明出处:Flutter学习笔记(33)--GestureDetector手势识别
这篇随笔主要记录的学习内容是GestureDetector手势识别,内容包括识别单击、双击、长按、组件拖拽和缩放处理。
- 单击、双击、长按
先看下demo,很简单,GestureDetector本身也是一个组件,GestureDetector识别其内部子组件的手势动作,GestureDetector的构造方法内给我们提供了onTap单击、onDoubleTap双击、onLongPress长按的是回调方法。
识别到用户的手势操作后会执行对应的回调方法,demo的处理就是简单的更新一下text的文案。
import 'package:flutter/material.dart'; class GestureDetectorDemo extends StatefulWidget { @override StatecreateState() { return _GestureDetectorDemo(); } } class _GestureDetectorDemo extends State { String _operation = "No Gesture detected!"; //保存事件名 @override Widget build(BuildContext context) { return MaterialApp( title: 'GestureDetectorDemo', home: new Scaffold( appBar: AppBar( title: Text('GestureDetectorDemo'), leading: Icon(Icons.arrow_back), ), body: new GestureDetector( child: Container( alignment: Alignment.center, color: Colors.red, width: 300, height: 200, child: Text( _operation, style: TextStyle(color: Colors.teal), ), ), onTap: () => setState(() => _operation = 'onTap'),//单机回调 onDoubleTap: () => setState(() => _operation = 'onDoubleTap'),//双击回调 onLongPress: () => setState(() => _operation = 'onLongPress'),//长按回调 ), ), ); } }
注:这里要说明一下,如果同时监听的onTap和onDoubleTap这两个事件的话,onTap会有200ms的延时,因为因为用户在点击一次之后很有可能会再点击一次来触发双击的事件,所以GestureDetector会等一段时间来确定用户是不是要双击,如果只是监听了onTap而没有监听onDoubleTap的话,就不会有延时了。
- 组件拖动
老样子先看demo再讲解:
import 'package:flutter/material.dart'; class GestureDragDemo extends StatefulWidget { @override StatecreateState() { return _GestureDragDemoState(); } } class _GestureDragDemoState extends State { double _top = 0.0; //距离顶部的偏移量 double _left = 0.0; //距离底部的偏移量 @override Widget build(BuildContext context) { return MaterialApp( title: 'GestureDragDemo', home: Scaffold( appBar: AppBar( title: Text('GestureDragDemo'), leading: Icon(Icons.keyboard_backspace), ), body: Stack( children: [ Positioned( top: _top, left: _left, child: GestureDetector( child: CircleAvatar( backgroundColor: Colors.red, child: Text( 'A', style: TextStyle(color: Colors.white), ), ), onPanDown: (DragDownDetails downDetails) { //手指按下时会执行此回调 // print('手指按下的位置:$downDetails.globalPosition'); }, onPanUpdate: (DragUpdateDetails dragUpdateDetails) { //手指滑动时会执行次回调 setState(() { //手指滑动时会多次触发onPanUpdate回调,更新偏移量并重新绘制 //dragUpdateDetails.delta.dx获取y轴方向的偏移量 _top += dragUpdateDetails.delta.dy; //dragUpdateDetails.delta.dy获取x轴方向的偏移量 _left += dragUpdateDetails.delta.dx; }); }, onPanEnd: (DragEndDetails dragEndDetails) { //打印滑动结束时在x、y轴上的速度 // print(dragEndDetails.velocity); }, ), ), ], )), ); } }
DragDownDetails.globalPosition
:当用户按下时,此属性为用户按下的位置相对于屏幕(而非父组件)原点(左上角)的偏移。DragUpdateDetails.delta
:当用户在屏幕上滑动时,会触发多次Update事件,delta
指一次Update事件的滑动的偏移量。DragEndDetails.velocity
:该属性代表用户抬起手指时的滑动速度(包含x、y两个轴的),示例中并没有处理手指抬起时的速度,常见的效果是根据用户抬起手指时的速度做一个减速动画。
也很简单,我们主要看下onPanUpdate这个回调方法,在我们手指滑动的过程中,会多次执行这个回调,在回调中我们处理下x、y方向的偏移量让后重新绘制就ok了。
偏移量打印:
- 单一方向拖动
上面的拖动是可以往任意方向拖动的,在日常的开发中,有可能会遇到只允许水平(拼图验证)或竖直方向上进行拖动,DestureDetector也为我们提供了对应的响应事件:
看下demo示例:
import 'package:flutter/material.dart'; class GestureDragDemo extends StatefulWidget { @override StatecreateState() { return _GestureDragDemoState(); } } class _GestureDragDemoState extends State { double _top = 0.0; //距离顶部的偏移量 double _left = 0.0; //距离底部的偏移量 @override Widget build(BuildContext context) { return MaterialApp( title: 'GestureDragDemo', home: Scaffold( appBar: AppBar( title: Text('GestureDragDemo'), leading: Icon(Icons.keyboard_backspace), ), body: Stack( children: [ Positioned( top: _top, left: _left, child: GestureDetector( child: CircleAvatar( backgroundColor: Colors.red, child: Text( 'A', style: TextStyle(color: Colors.white), ), ), onPanDown: (DragDownDetails downDetails) { //手指按下时会执行此回调 // print('手指按下的位置:$downDetails.globalPosition'); }, // onPanUpdate: (DragUpdateDetails dragUpdateDetails) { // //手指滑动时会执行次回调 // setState(() { // //手指滑动时会多次触发onPanUpdate回调,更新偏移量并重新绘制 // //dragUpdateDetails.delta.dx获取y轴方向的偏移量 // _top += dragUpdateDetails.delta.dy; // print('Y:$dragUpdateDetails.delta.dy'); // //dragUpdateDetails.delta.dy获取x轴方向的偏移量 // _left += dragUpdateDetails.delta.dx; // print('X:$dragUpdateDetails.delta.dx'); // }); // }, onHorizontalDragUpdate: (DragUpdateDetails dragUpdateDetails){ setState(() { _left += dragUpdateDetails.delta.dx; }); }, onPanEnd: (DragEndDetails dragEndDetails) { //打印滑动结束时在x、y轴上的速度 // print(dragEndDetails.velocity); }, ), ), ], )), ); } }
- 缩放
import 'package:flutter/material.dart'; class GestureScaleDemo extends StatefulWidget{ @override StatecreateState() { return _GestureScaleDemoState(); } } class _GestureScaleDemoState extends State { double _width = 200.0; @override Widget build(BuildContext context) { return MaterialApp( title: 'GestureScaleDemo', home: Scaffold( appBar: AppBar( title: Text('GestureScaleDemo'), ), body: Center( child: GestureDetector( child: Image.asset('images/banner.png',width: _width), onScaleUpdate: (ScaleUpdateDetails scaleUpdateDetails){ setState(() { //缩放倍数在0.8到10倍之间 _width=200*scaleUpdateDetails.scale.clamp(.8, 10.0); }); }, ), ), ), ); } }