动态

详情 返回 返回

flutter系列之:移動端手勢的具體使用 - 动态 详情

簡介

之前我們介紹了GestureDetector的定義和其提供的一些基本的方法,GestureDetector的好處就是可以把任何一個widget都賦予類似button的功能。

今天將會通過幾個具體的例子來講解一下GestureDetector的具體使用。

賦予widget可以點擊的功能

一般情況下,我們的普通widget,比如文本是不能進行交互的,但是如果將其用GestureDetector進行包裝之後,就可以將其偽裝成為一個button。

比如我們有這樣一個偽裝成button的Container:

Container(
        padding: const EdgeInsets.all(12.0),
        decoration: BoxDecoration(
          color: Colors.green,
          borderRadius: BorderRadius.circular(8.0),
        ),
        child: const Text('My Button'),
      )

這個Container的本質是一個Text,這個Container本身是沒有交互功能的,那麼如何對其添加交互功能呢?

最簡單的辦法就是將其使用GestureDetector包裝起來,如下所示:

GestureDetector(
      // The custom button
      child: Container(
        padding: const EdgeInsets.all(12.0),
        decoration: BoxDecoration(
          color: Colors.green,
          borderRadius: BorderRadius.circular(8.0),
        ),
        child: const Text('My Button'),
      ),
    )

接下來我們還要為其添加對應的手勢,這裏我們添加一個onTap方法,

GestureDetector(
      onTap: ()=> showDialog<String>(
        context: context,
        builder: (BuildContext context) => AlertDialog(
          title: const Text('基本手勢'),
          content: const Text('這是基本的手勢,你學會了嗎?'),
          actions: <Widget>[
            TextButton(
              onPressed: () => Navigator.pop(context, 'Cancel'),
              child: const Text('Cancel'),
            ),
            TextButton(
              onPressed: () => Navigator.pop(context, 'OK'),
              child: const Text('OK'),
            ),
          ],
        ),
      ),
      ...

這裏onTap會調用一個showDialog來彈出一個對話框,運行之後結果如下:

會動的組件

在上面的例子中,我們用手去tap按鈕是沒有互動效果的,也就是説按鈕是不會變化的。

那麼有沒有可能模擬手指的按壓效果呢?

答案是肯定的,flutter為我們提供了一個InkWell組件,這樣手指按壓下組件會產生波紋的效果。

那麼InkWell和GestureDetector有什麼聯繫呢?

InkWell和GestureDetector很類似,都提供了對手勢的支持。

在InkWell中提供了多種GestureTapCallback接口,用接收手勢的回調,非常的方便。

在使用上,InkWell和GestureDetector也很類似,我們可以完全照搬GestureDetector的用法。

還是上面的例子,我們可以將GestureDetector替換成為InkWell,如下所示:

  Widget build(BuildContext context) {
    return InkWell(
      onTap: () {
        ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
          content: Text('Tap'),
        ));
      },
      child: const Padding(
        padding: EdgeInsets.all(12.0),
        child: Text('Flat Button'),
      ),
    );
  }

這裏,為了更好的觀察手勢按壓之後的效果,這裏onTap選擇展示一個flutter自帶的SnackBar。

可刪除的組件

在app中的手勢應用上,有一個比較常見的用法就是在list列表中,向左滑動一個item,會出現刪除的按鈕,這種滑動刪除的效果,如何在flutter中實現呢?

flutter提供了一個Dismissible的組件來實現這個效果。

我們先來看下Dismissible的定義:

class Dismissible extends StatefulWidget {
    const Dismissible({
    required Key key,
    required this.child,
    this.background,
    this.secondaryBackground,
    this.confirmDismiss,
    this.onResize,
    this.onUpdate,
    this.onDismissed,
    this.direction = DismissDirection.horizontal,
    this.resizeDuration = const Duration(milliseconds: 300),
    this.dismissThresholds = const <DismissDirection, double>{},
    this.movementDuration = const Duration(milliseconds: 200),
    this.crossAxisEndOffset = 0.0,
    this.dragStartBehavior = DragStartBehavior.start,
    this.behavior = HitTestBehavior.opaque,
  }) : assert(key != null),
       assert(secondaryBackground == null || background != null),
       assert(dragStartBehavior != null),
       super(key: key);

可以看到Dismissible是一個StatefulWidget,它有兩個必須的參數分別是key和child。

key用來標記要刪除item的id,child是可以滑動刪除的組件。

為了演示方便,我們使用ListView來展示如何使用Dismissible。

首先我們構建一個items的list,裏面包含了每個item要展示的內容:

 final items = List<String>.generate(10, (i) => '動物 ${i + 1}');

然後使用ListView的builder方法來構建items。並且將每個items封裝到Dismissible中去:

body: ListView.builder(
          itemCount: items.length,
          itemBuilder: (context, index) {
            final item = items[index];
            return Dismissible(
              key: Key(item),
              onDismissed: (direction) {
                setState(() {
                  items.removeAt(index);
                });
                ScaffoldMessenger.of(context)
                    .showSnackBar(SnackBar(content: Text('$item 被刪除了')));
              },
              child: ListTile(
                title: Text(item),
              ),
            );
          },
        )

這裏Dismissible的child是ListTile組件,裏面的具體內容就是Text。

現在Dismissible實際上就可以工作了,當你滑動ListTile的時候,對應的item就會被刪除。

為了明顯起見,我們可以給Dismissible添加一個background屬性,這樣滑動刪除的時候就有了一個背景顏色:

              background: Container(color: Colors.red),

另外,Dismissible還有一個confirmDismiss屬性,可以用來判斷是否真的要滑動刪除,比如我們只允許從右到左滑動刪除,那麼可以這樣做:

Dismissible(
  ...
confirmDismiss:confirmResult,
...
)

  Future<bool> confirmResult(DismissDirection direction) async {
    if(direction == DismissDirection.endToStart){
      return true;
    }
    return false;
  }

這裏的confirmResult是一個異步函數,它接收一個DismissDirection的參數,這個參數表示的是滑動刪除的方向,我們可以通過這個方向來判斷是否真正的進行刪除操作。

總結

以上就是日常手勢的基本使用了,我們可以通過GestureDetector,InkWell和Dismissible來和手勢進行結合來實現相應的功能。

本文的例子:https://github.com/ddean2009/learn-flutter.git

更多內容請參考 www.flydean.com

最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!

歡迎關注我的公眾號:「程序那些事」,懂技術,更懂你!

user avatar lenglingx 头像 yizhidanshendetielian 头像 chaochenyinshi 头像 beishangdeyadan 头像 mecode 头像 xiangzhihong 头像 zhuifengdekukafei 头像 sheyingshichenjian 头像 sevencode 头像 sulf 头像 jinjiedefarmer 头像 jeremylai7 头像
点赞 15 用户, 点赞了这篇动态!
点赞

Add a new 评论

Some HTML is okay.