Flutterでキャンセルボタンを独立させた選択肢としてボトムに表示する Cupertino ver.
iOSアプリでよくみる以下のようなキャンセルボタンが独立したモーダルを画面下に表示したい。
環境
- macOS Big Sur 11.3.1
- Flutter 2.2.0
問題点1: 名前がわからない
- これはなんていうWidget?
Webの経験はあるものの、アプリ開発についてはまったくわからず、🔼がなんて呼ばれるものなのかが分からず。。。
たまたま、以下の本を持っていることを思い出し「もしかして・・・」と思い調べたところ、「アクションシート」というものらしい。
一般的な呼称がわかったので、「Flutter アクションシート」のようなキーワードで検索したところいくつか記事を発見。
どうやら、CupertinoActionSheet
というWidgetを使えばよさげ。
使ってみる
勉強用につくったTODOアプリに組み込む形で試してみる。
動きとしては、タスクを削除するときの確認モーダルとして以下を表示させたい。
- タスク名 + 注意文言
- Delete Task(削除後はタスク一覧画面に遷移)
- Cancel
実装
// 省略
IconButton(
onPressed: () {
showCupertinoModalPopup<void>(
context: context,
builder: (BuildContext context) {
return CupertinoActionSheet(
message: Text(
// ignore: lines_longer_than_80_chars
'${snapshot.data!["taskName"].toString()} will be permanentally deleted',
style: const TextStyle(fontSize: 15),
),
actions: <Widget>[
CupertinoActionSheetAction(
child: const Text('Delete Task'),
isDestructiveAction: true,
onPressed: () {
TaskLogic.delete(docId);
Navigator.pop(context);
},
)
],
cancelButton: CupertinoActionSheetAction(
child: Text("Cancel"),
onPressed: () {
Navigator.pop(context);
},
),
);
});
},
icon: const Icon(Icons.delete),
)
// 省略
いい感じにできた。Webの場合はこの形にデザインする必要があるけど、Flutterだと基本的なデザインはすでにされているのでとてもありがたい。
問題点2: タスクを削除したあとにアプリのホーム画面に戻る動きがおかしい
見た目はほぼ完璧にやりたかったものができたが、このままだと問題が1点あって「Delete Task」したときにずっとローディングになってしまう。
アクションシートがRouteに追加されるので、pop()
したときに表示されるのがタスク詳細画面になってしまい、すでに削除されたデータを読み込もうとしてずっとローディングが表示されているという事象のよう。
- タスク詳細画面
- アクションシート
- タスク詳細画面 ←存在しないデータを読み込もうとしてずっとローディングが表示
2.のアクションシートで「Delete Task」をしたときにタスク詳細ではなく、タスク一覧画面に遷移させるようにしたい。
タスク一覧画面は初期画面なので、popUntil()
を使えばよさげ。
こちらを参考に事前定義をせずに初期画面に遷移するよう修正。
CupertinoActionSheetAction(
child: const Text('Delete Task'),
isDestructiveAction: true,
onPressed: () async {
await TaskLogic.delete(docId);
// popUntilで最初のページまで戻る
Navigator.of(context)
.popUntil((route) => route.isFirst);
},
)
これで想定した動きが実装できた。
最後に
今回、ルートを事前定義せずに遷移させる方法で実装したけど、あらかじめルートを定義する方法でもやってみたい。
また、今回はCupertinoActionSheet
を使ったが、iOS特有なWidgetなのでMaterial Componentsを使って似たようなUIにしたほうがいいかも。
-> Androidでも表示されるっぽい。(2021/06/27追記)
Discussion