本文首發於公衆號「劉望舒」前端
ReactNative入門系列 React Native組件 Flutter基礎系列java
移動開發中,用戶交互是一個重要的環節,在Android中的觸摸、點擊、滑動等事件處理都提供了相關的Api,在Flutter中也是同樣的,是由Widget來實現的。 Flutter中的手勢系統有兩個獨立的層。第一層是原始指針事件(pointer events),它描述了屏幕上指針,好比觸摸、鼠標、觸控筆的位置和移動。 第二層是手勢,由一個或多個指針移動組成的動做會被識別爲不一樣的手勢。程序員
指針表示用戶與設備屏幕交互的原始數據。有四種類型的指針事件:app
在指針按下時,Flutter框架會對當前應用程序執行命中測試,以肯定指針與屏幕接觸的位置存在哪一個Widget上,而後將PointerDownEvent事件(以及該指針的後續事件)調度到命中測試找到的最內部的Widget,事件的分配路徑爲:從最裏面的Widget到樹的根路徑上的全部Widget。框架
手勢表示由一個或多個指針移動組成的動做。主要有如下幾種:less
點擊ide
onTapDown:指針已經在特定位置與屏幕接觸。 onTapUp:指針中止在特定位置與屏幕接觸。 onTap :點擊事件觸發。 onTapCancel: 先前指針觸發的onTapDown不會再觸發點擊事件。測試
雙擊動畫
onDoubleTap:用戶快速連續兩次在同一位置輕敲屏幕。ui
長按
onLongPress:指針在相同位置長時間保持與屏幕接觸。
垂直拖動
onVerticalDragStart:指針已經與屏幕接觸並可能開始垂直移動。 onVerticalDragUpdate 指針與屏幕接觸並已沿垂直方向移動。 onVerticalDragEnd 先前與屏幕接觸並垂直移動的指針再也不與屏幕接觸,而且在中止接觸屏幕時以特定速度移動。
水平拖動
onHorizontalDragStart:指針已經接觸到屏幕並可能開始水平移動 onHorizontalDragUpdate:指針與屏幕接觸並已沿水平方向移動 onHorizontalDragEnd:先前與屏幕接觸並水平移動的指針再也不與屏幕接觸,並在中止接觸屏幕時以特定速度移動。
如何對這些手勢進行檢測呢?可使用GestureDetector。
要想檢測單擊、雙擊、垂直拖動等手勢,只要用GestureDetector嵌套要檢測手勢Widget並實現想要監聽的手勢的方法就行。
import 'package:flutter/material.dart';
void main() => runApp(GestureDetectorWidget());
class GestureDetectorWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter",
home: Scaffold(
appBar: AppBar(
title: Text("GestureDetector示例"),
),
body: Center(
child: GestureDetector(
child: Text('手勢識別'),
onTap: () {
print('點擊');
},
onDoubleTap: () {
print('雙擊');
},
onLongPress: () {
print('長按');
},
onHorizontalDragStart: (DragStartDetails details) {
print('水平拖動');
},
),
),
),
);
}
}
複製代碼
只須要在手勢識別這個文字上進行操做,那麼對應的手勢就會被打印出來。
滑動刪除這個操做很常見,好比在一個列表中,咱們向左滑動,就會直接刪除一個條目或者給出刪除提示選項。Flutter提供了Dismissible來幫助咱們實現滑動刪除。
import 'package:flutter/material.dart';
void main() => runApp(DismissibleWidget(
items: new List<String>.generate(300, (i) => "第$i行"),
));
class DismissibleWidget extends StatelessWidget {
final List<String> items;
DismissibleWidget({@required this.items});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('Dismissible示例'),
),
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
return Dismissible(
key: Key(item),
onDismissed: (direction) {
items.removeAt(index);
print(index);
},
child: ListTile(
leading: Icon(Icons.access_time),
title: Text('${items[index]}'),
),
);
},
),
),
);
}
}
複製代碼
這個例子和ListView的例子相似,主要的變化就是用Dismissible來嵌套ListTile。當執行刪除操做時,ListView中的onDismissed方法會被回調,咱們能夠直接在onDismissed方法中將被刪除的item從List中移除。
咱們向左滑動第一個和第二個item,會出現刪除的動畫,結果以下圖所示。