Flutter基礎(八)手勢相關Widget:GestureDetector和Dismissible

劉望舒發表於2019-07-15

本文首發於公眾號「劉望舒」

ReactNative入門系列 React Native元件 Flutter基礎系列

前言

移動開發中,使用者互動是一個重要的環節,在Android中的觸控、點選、滑動等事件處理都提供了相關的Api,在Flutter中也是一樣的,是由Widget來實現的。 Flutter中的手勢系統有兩個獨立的層。第一層是原始指標事件(pointer events),它描述了螢幕上指標,比如觸控、滑鼠、觸控筆的位置和移動。 第二層是手勢,由一個或多個指標移動組成的動作會被識別為不同的手勢。

1.指標事件

指標表示使用者與裝置螢幕互動的原始資料。有四種型別的指標事件:

  • PointerDownEvent:指標接觸到螢幕的特定位置。
  • PointerMoveEvent: 指標已從螢幕上的一個位置移動到另一個位置。
  • PointerUpEvent: 指標已停止接觸螢幕。
  • PointerCancelEvent:此指標的輸入不再指向此應用,通俗來講就是事件取消。

在指標按下時,Flutter框架會對當前應用程式執行命中測試,以確定指標與螢幕接觸的位置存在哪個Widget上,然後將PointerDownEvent事件(以及該指標的後續事件)排程到命中測試找到的最內部的Widget,事件的分配路徑為:從最裡面的Widget到樹的根路徑上的所有Widget。

2.手勢

手勢表示由一個或多個指標移動組成的動作。主要有以下幾種:

點選

onTapDown:指標已經在特定位置與螢幕接觸。 onTapUp:指標停止在特定位置與螢幕接觸。 onTap :點選事件觸發。 onTapCancel: 先前指標觸發的onTapDown不會再觸發點選事件。

雙擊

onDoubleTap:使用者快速連續兩次在同一位置輕敲螢幕。

長按

onLongPress:指標在相同位置長時間保持與螢幕接觸。

垂直拖動

onVerticalDragStart:指標已經與螢幕接觸並可能開始垂直移動。 onVerticalDragUpdate 指標與螢幕接觸並已沿垂直方向移動。 onVerticalDragEnd 先前與螢幕接觸並垂直移動的指標不再與螢幕接觸,並且在停止接觸螢幕時以特定速度移動。

水平拖動

onHorizontalDragStart:指標已經接觸到螢幕並可能開始水平移動 onHorizontalDragUpdate:指標與螢幕接觸並已沿水平方向移動 onHorizontalDragEnd:先前與螢幕接觸並水平移動的指標不再與螢幕接觸,並在停止接觸螢幕時以特定速度移動。

如何對這些手勢進行檢測呢?可以使用GestureDetector。

3.使用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('水平拖動');
            },
          ),
        ),
      ),
    );
  }
}
複製程式碼

只需要在手勢識別這個文字上進行操作,那麼對應的手勢就會被列印出來。

V5ddxA.png

4.使用Dismissible

滑動刪除這個操作很常見,比如在一個列表中,我們向左滑動,就會直接刪除一個條目或者給出刪除提示選項。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中移除。

V5dBrt.png

我們向左滑動第一個和第二個item,會出現刪除的動畫,結果如下圖所示。

V5wpdK.png


這裡不僅分享大前端、Android、Java等技術,還有程式設計師成長類文章。
Flutter基礎(八)手勢相關Widget:GestureDetector和Dismissible

相關文章