GestureDetector是Flutter的手勢檢測器,它會嘗試識別與其非null的回調相對應的手勢。若是此Widget組件具備子控件,那麼它的大小調整行爲將聽從該子控件件。若是它沒有子控件,那麼它將變大以適合父控件。git
默認狀況下,帶有不可見子控件的手勢檢測器會忽略觸摸;能夠經過行爲控制此邏輯。GestureDetector還監聽可訪問性事件,並將其映射到callback回調。若要忽略可訪問性事件,請將ExcludeFromSemantics設置爲true。github
Flutter中的手勢系統有兩個獨立的層。第一層爲原始指針(pointer)事件,它描述了屏幕上指針(例如,觸摸、鼠標和觸控筆)的位置和移動。 第二層爲手勢,描述由一個或多個指針移動組成的語義動做,如拖拽、縮放、雙擊、長按等。bash
在flutter中,手勢表示能夠從多個單獨的指針事件(甚至多是多個單獨的指針)識別的語義動做(例如點擊,拖拽和縮放)。 完整的一個手勢能夠分發多個事件,對應於手勢的生命週期(例如,拖拽開始,拖拽更新和拖拽結束):app
單擊less
雙擊ide
長按函數
垂直拖拽工具
水平拖拽ui
Object —> Diagnosticable —> DiagnosticableTree —> Widget —> StatelessWidget —> GestureDetectorspa
Draggable({Key key,
@required Widget child,
@required Widget feedback,
T data,
Axis axis,
Widget childWhenDragging,
Offset feedbackOffset: Offset.zero,
DragAnchor dragAnchor: DragAnchor.child,
Axis affinity,
int maxSimultaneousDrags,
VoidCallback onDragStarted,
DraggableCanceledCallback onDraggableCanceled,
DragEndCallback onDragEnd,
VoidCallback onDragCompleted,
bool ignoringFeedbackSemantics: true })
複製代碼
dragStartBehavior → DragStartBehavior 肯定處理拖拽開始行爲的方式
excludeFromSemantics → bool 是否從語義樹中排除這些手勢。
例如,用於顯示工具提示的長按手勢被排除,由於工具提示自己直接包含在語義樹中,所以具備顯示它的手勢將致使信息的重複。
onDoubleTap → GestureTapCallback 用戶已快速連續兩次在同一位置使用主按鈕輕觸屏幕。
onForcePressEnd → GestureForcePressEndCallback 指針再也不與屏幕接觸。
onForcePressPeak → GestureForcePressPeakCallback 指針與屏幕接觸並以最大力按下。力量至少是 ForcePressGestureRecognizer.peakPressure。
onForcePressStart → GestureForcePressStartCallback 指針與屏幕接觸,並用足夠的力按壓以啓動壓力。力量至少是 ForcePressGestureRecognizer.startPressure。
onForcePressUpdate → GestureForcePressUpdateCallback 指針與屏幕接觸,以前已經經過了 ForcePressGestureRecognizer.startPressure,而且要麼在屏幕的平面上移動,要麼用不一樣的力按壓屏幕,要麼同時按兩個屏幕。
onHorizontalDragCancel → GestureDragCancelCallback 先前觸發onHorizontalDragDown的指針未完成觸發了取消。
onHorizontalDragDown → GestureDragDownCallback 指針已經過主按鈕與屏幕接觸,並可能開始水平移動。
onHorizontalDragEnd → GestureDragEndCallback 以前與主屏幕接觸而且水平移動的指針再也不與屏幕接觸,而且當它中止接觸屏幕時以特定速度移動。
onHorizontalDragStart → GestureDragStartCallback 指針已經過主按鈕與屏幕接觸,並開始水平移動。
onHorizontalDragUpdate → GestureDragUpdateCallback 與主按鈕接觸而且水平移動的指針在水平方向上移動。
onLongPress → GestureLongPressCallback 當識別出具備主按鈕的長按手勢時調用。
onLongPressEnd → GestureLongPressEndCallback 使用主按鈕觸發長按的指針已中止接觸屏幕。
onLongPressMoveUpdate → GestureLongPressMoveUpdateCallback 使用主按鈕長按後,指針已被拖動。
onLongPressStart → GestureLongPressStartCallback 當識別出具備主按鈕的長按手勢時調用。
onLongPressUp → GestureLongPressUpCallback 使用主按鈕觸發長按的指針已中止接觸屏幕。
onPanCancel → GestureDragCancelCallback 先前觸發onPanDown的指針未完成。
onPanDown → GestureDragDownCallback 指針已經過主按鈕與屏幕接觸,並可能開始移動。
onPanEnd → GestureDragEndCallback 先前經過主按鈕與屏幕接觸而且移動的指針再也不與屏幕接觸,而且當它中止接觸屏幕時以特定速度移動。
onPanStart → GestureDragStartCallback 觸摸點與屏幕接觸,並已開始移動。
onPanUpdate → GestureDragUpdateCallback 屏幕上的觸摸點位置每次改變時,都會觸發該回調。
onScaleEnd → GestureScaleEndCallback 指針再也不與屏幕接觸。
onScaleStart → GestureScaleStartCallback 與屏幕接觸的指針已創建焦點,初始比例爲1.0。
onScaleUpdate → GestureScaleUpdateCallback 與屏幕接觸的指針表示新的焦點和/或比例。
onSecondaryTapCancel → GestureTapCancelCallback 先前觸發onSecondaryTapDown的指針不會最終致使點擊。
onSecondaryTapDown → GestureTapDownCallback 可能致使使用輔助按鈕敲擊的指針已在特定位置與屏幕聯繫。
onSecondaryTapUp → GestureTapUpCallback 將觸發帶有輔助按鈕的敲擊的指針已中止在特定位置接觸屏幕。
onTap → GestureTapCallback 帶主按鈕的點擊事件觸發源頭。
onTapCancel → GestureTapCancelCallback 先前觸發onTapDown的指針不會致使點擊。
onTapDown → GestureTapDownCallback 可能致使使用主按鈕敲擊的指針已在特定位置與屏幕聯繫。
onTapUp → GestureTapUpCallback 將觸發帶主按鈕的敲擊的指針已中止在特定位置接觸屏幕。
onVerticalDragCancel → GestureDragCancelCallback 先前觸發onVerticalDragDown的指針未完成。
onVerticalDragDown → GestureDragDownCallback 指針已經過主按鈕與屏幕接觸,並可能開始垂直移動。
onVerticalDragEnd → GestureDragEndCallback 先前與主屏幕接觸而且垂直移動的指針再也不與屏幕接觸,而且當它中止接觸屏幕時以特定速度移動。
onVerticalDragStart → GestureDragStartCallback 指針已經過主按鈕與屏幕接觸,並已開始垂直移動。
onVerticalDragUpdate → GestureDragUpdateCallback 與主按鈕接觸而且垂直移動的指針在垂直方向上移動。
這裏經過一個demo,用GestureDetector對Container組件進行手勢識別。在觸發相應事件後,Container上顯示事件名,爲了增大點擊區域,將Container設置爲200×200,代碼以下:
import 'package:flutter/material.dart';
class GestureDetectorTestRoute extends StatefulWidget {
@override
_GestureDetectorTestRouteState createState() =>
new _GestureDetectorTestRouteState();
}
class _GestureDetectorTestRouteState extends State<GestureDetectorTestRoute> {
String _operation = "No Gesture detected!";
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: Text("GestureDetectorTest"),
),
body: Center(
child: GestureDetector(
child: Container(
alignment: Alignment.center,
color: Colors.blue,
width: 200.0,
height: 200.0,
child: Text(
_operation,
style: TextStyle(
color: Colors.white,
fontSize: 14,
decoration: TextDecoration.none),
),
),
onTap: () => updateText("onTap"), //單擊
onDoubleTap: () => updateText("onDoubleTap"), //雙擊
onLongPress: () => updateText("onLongPress"), //長按
),
),
);
}
//更新文本
void updateText(String text) {
setState(() {
_operation = text;
});
//提示
showSnackBar(text);
}
var _scaffoldKey = new GlobalKey<ScaffoldState>();
void showSnackBar(String message) {
var snackBar = SnackBar(
content: Text(message),
backgroundColor: Colors.lightGreen,
duration: Duration(milliseconds: 400));
_scaffoldKey.currentState.showSnackBar(snackBar);
}
}
複製代碼
效果圖以下:
注意: 若同時監聽onTap和onDoubleTap事件,當用戶觸發tap事件時,會有200毫秒左右的延時。這是由於當用戶點擊完以後極可能會再次點擊以觸發雙擊事件,因此GestureDetector源碼內部會等200毫秒時間來肯定是否爲雙擊事件。若是用戶只監聽了onTap(沒有監聽onDoubleTap)事件則回調沒有延時。
import 'package:flutter/material.dart';
class DragTest extends StatefulWidget {
@override
_DragTestState createState() => new _DragTestState();
}
class _DragTestState extends State<DragTest>
with SingleTickerProviderStateMixin {
double _top = 0.0; //距頂部的偏移
double _left = 0.0; //距左邊的偏移
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("DragTest"),
),
body: Stack(
children: <Widget>[
Positioned(
top: _top,
left: _left,
child: GestureDetector(
child: CircleAvatar(
child: Text("Draggable Text", textAlign: TextAlign.center),
radius: 50),
//手指按下時會觸發此回調
onPanDown: (DragDownDetails e) {
//打印手指按下的位置(屏幕)
print("用戶手指按下:${e.globalPosition}");
},
//手指滑動時會觸發此回調
onPanUpdate: (DragUpdateDetails e) {
//用戶手指滑動時,更新偏移,從新構建
setState(() {
_left += e.delta.dx;
_top += e.delta.dy;
});
},
onPanEnd: (DragEndDetails e) {
//打印滑動結束時在x、y軸上的速度
print(e.velocity);
},
),
)
],
),
);
}
}
複製代碼
效果圖以下:
除了單擊/雙擊/拖拽等事件,GestureDetector能夠監聽縮放事件。下面咱們演示一個簡單的圖片縮放效果,示例代碼以下:
class _ScaleTestRouteState extends State<_ScaleTestRoute> {
double _width = 200.0; //經過修改圖片寬度來達到縮放效果
@override
Widget build(BuildContext context) {
return Center(
child: GestureDetector(
//指定寬度,高度自適應
child: Image.asset("./images/sea.png", width: _width),
onScaleUpdate: (ScaleUpdateDetails details) {
setState(() {
//縮放倍數在0.8到10倍之間
_width=200*details.scale.clamp(.8, 10.0);
});
},
),
);
}
}
複製代碼
效果圖以下:
經過這篇文章,咱們瞭解了flutter 所提供的GestureDetector手勢檢測器的一些基本概念及能力,它內部封裝了諸多API,讓咱們能夠很高效快速開發應用。經過文章的內容講述,咱們知道如何去監聽單擊/雙擊/拖拽等事件及處理用戶的交互邏輯。固然,觸摸交互模型裏面不可避免地會出現事件競爭和事件衝突問題,本篇文章因爲篇幅問題就沒有進行講解了,下篇文章咱們將會側重講述flutter中的事件競爭及衝突問題。
![]() xiaosongzeem |