[読書会]スワイプ(swipe)して閉じる

 「スワイプで削除」パターンは、多くのモバイルアプリで一般的です。
(例えば、メールアプリを作成する際、ユーザーがスワイプでメールメッセージをリストから削除できるようにしたいという場合に有効です。)

 FlutterはDismissibleウィジェットを提供することで、このタスクを簡単にします。
以下の手順で、スワイプによる却下を実装する方法を学びましょう。

  1. アイテムのリスト作成する。
  2. 各アイテムDismissibleウィジェットでラップする。
  3. インジケータ表示する。

1.アイテムリスト作成

 まず、アイテムのリストを作成します。
 (リストの詳しい作り方については、Working with long listsを参照して下さい。)

(1)データソース作成

 アイテムリストを用意します。(ここでは、20個の文字列のリストを生成します。)

20個のサンプル・アイテムの宣言(例):
final items = List<String>.generate(
 20, (i) => 'Item ${i + 1}'
);

(2)データソースをリストに変換

 リスト内の各項目を画面上に表示します。

リスト内の各項目を画面上に表示する(例):
ListView.builder(
  itemCount: items.length,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text(items[index]),
    );
  },
)

2.各項目を Dismissible ウィジェットでラップ

 ここでは、Dismissibleウィジェットを使い、ユーザがリストからアイテムスワイプ可能にします。

 ユーザがアイテムスワイプした後、リストからアイテム削除し、スナックバーを表示します。実際のアプリでは、Webサービスやデータベースからアイテム削除するなど、より複雑なロジックを実行する必要があるかもしれません。

 Dismissibleウィジェットを返すようにitemBuilder()関数更新する。

Dart
itemBuilder: (context, index) {
  final item = items[index];
  return Dismissible(
    //各 Dismissible にはキーが含まれている必要があります。
    //キーを使用すると、Flutter はウィジェットを一意に識別できます。
    key: Key(item),
    //アイテムがスワイプされた後に何をするかをアプリに
    //指示する関数を提供します。
    onDismissed: (direction) {
      //データ ソースから項目を削除します。
      setState(() {
        items.removeAt(index);
      });

      //スナックバーを表示する。
      ScaffoldMessenger.of(context)
        .showSnackBar(SnackBar(
          content: Text('$item dismissed')
        )
      );
    },
    child: ListTile(
      title: Text(item),
    ),
  );
},

3.インジケータの表示

 ここでは、ユーザーがリストから項目スワイプすることはできるが、スワイプしたときに何が起こるかを視覚的に示すことはできません。アイテム削除されたことを知らせるには、アイテムスワイプすると「leave behind」インジケータが表示されます。インジケータ赤い背景にしてあります。

 インジケータ追加するには、Dismissiblebackgroundパラメータを指定します。

アイテムがスワイプされた時、赤い背景を表示する(例):
  ScaffoldMessenger.of(context)
    .showSnackBar(SnackBar(
      content: Text('$item dismissed')
    )
  );
},
//アイテムがスワイプされた時、赤い背景を表示しています。
background: Container(color: Colors.red),
child: ListTile(
  title: Text(item),
),

4.サンプルコード

サンプルコード:
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

//MyAppはStatefulWidgetです。これにより、イテムが削除された時に
//ウィジェットの状態を更新することができます。
class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  MyAppState createState() {
    return MyAppState();
  }
}

class MyAppState extends State<MyApp> {
  //20個のアイテムを持つリストを生成します。
  //アイテムは「Item 1」「Item 2」... のように表示されます。
  final items = List<String>.generate(
    20, (i) => 'Item ${i + 1}'
  );

  @override
  Widget build(BuildContext context) {
    const title = 'Dismissing Items'; //アプリのタイトル

    return MaterialApp(
      title: title,
      theme: ThemeData(
        //カラースキームを指定してテーマを設定
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.deepPurple
        ),
      ),
      home: Scaffold(
        appBar: AppBar(
          title: const Text(title),
        ),
        //ListView.builderを使用して、リストを作成します。
        body: ListView.builder(
          itemCount: items.length, //リストのアイテム数を指定
          itemBuilder: (context, index) {
            final item = items[index]; //現在のアイテムを取得

            return Dismissible(
              //各DismissibleにはKeyが必要です。
              //KeyはFlutterがウィジェットを
              //一意に識別できるようにします。
              key: Key(item),
              //アイテムがスワイプされて消去された後に
              //アプリが行う処理を提供します。
              onDismissed: (direction) {
                //データソースからアイテムを削除します。
                setState(() {
                  //リストからアイテムを削除
                  items.removeAt(index);
                });

                //その後、スナックバーを表示します。
                ScaffoldMessenger.of(context)
                    .showSnackBar(SnackBar(
                      content: Text('$item dismissed')
                    )
                 );
              },
              //アイテムがスワイプされて削除される時に
              //赤い背景を表示します。
              background: Container(color: Colors.red),
              //リストのアイテムとしてListTileを使用します。
              child: ListTile(
                title: Text(item), //アイテム名を表示
              ),
            );
          },
        ),
      ),
    );
  }
}

コメントを残す