這篇隨筆主要記錄的學習內容是GestureDetector手勢識別,內容包括識別單擊、雙擊、長按、組件拖拽和縮放處理。 ...
如需轉載,請註明出處:Flutter學習筆記(33)--GestureDetector手勢識別
這篇隨筆主要記錄的學習內容是GestureDetector手勢識別,內容包括識別單擊、雙擊、長按、組件拖拽和縮放處理。
- 單擊、雙擊、長按
先看下demo,很簡單,GestureDetector本身也是一個組件,GestureDetector識別其內部子組件的手勢動作,GestureDetector的構造方法內給我們提供了onTap單擊、onDoubleTap雙擊、onLongPress長按的是回調方法。
識別到用戶的手勢操作後會執行對應的回調方法,demo的處理就是簡單的更新一下text的文案。
import 'package:flutter/material.dart'; class GestureDetectorDemo extends StatefulWidget { @override State<StatefulWidget> createState() { 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 State<StatefulWidget> createState() { return _GestureDragDemoState(); } } class _GestureDragDemoState extends State<GestureDragDemo> { 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: <Widget>[ 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 State<StatefulWidget> createState() { return _GestureDragDemoState(); } } class _GestureDragDemoState extends State<GestureDragDemo> { 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: <Widget>[ 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 State<StatefulWidget> createState() { 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); }); }, ), ), ), ); } }