概要
よくあるコレ(スワイプ削除)をFlutterで実装する方法です。
まずは原型
コードは以下のような状態とします。
flutter create
を行ったあと、少しだけ手を入れて静的なリストを一覧表示しています。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<String> itemList = ["item1", "item2", "item3", "item4", "item5"];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
itemCount: itemList.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text(itemList[index]),
),
);
},
),
);
}
}
見た目はこんな感じです。
Dismissibleでラッピングする
まずは、静的リストが生成されているCard部分をDismissibleでラッピングします。
// ~一部抜粋~ 以下部分をDismissibleで囲む
return Card(
child: ListTile(
title: Text(itemList[index]),
),
);
このようになります。
なお、Cardがスワイプされた時にどのCardがスワイプされたかが識別できるように一意な値を持たせる必要があります。一意な値はkey
で設定します。何を与えても良いですが、重複しない保証があるUniqueKeyを使用すると良いでしょう。
// ~一部抜粋~ Dismissibleで囲んでみた
return Dismissible(
key: UniqueKey(),
child: Card(
child: ListTile(
title: Text(itemList[index]),
),
),
);
ただ、実はスワイプ方向が指定されていないので左右どちらにでもスワイプできてしまいます。
スワイプ可能な方向を指定する
さすがに気持ちが悪いので、directionパラメータで方向を指定します。
DismissDirection.endToStart
が画面上では左から右を表します。
startToEnd
にすれば右から左になります。
return Dismissible(
key: UniqueKey(),
direction: DismissDirection.endToStart, //追加
child: Card(
child: ListTile(
title: Text(itemList[index]),
),
),
);
これで、右から左へはスワイプができなくなりました。
せっかくなので背景色を...
せっかくなので、スワイプ時に赤い背景が出るようにしてみます。
背景はbackgroundで追加することができます。
return Dismissible(
key: UniqueKey(),
direction: DismissDirection.endToStart,
//backgroundパラメータを追加
background: Container(
alignment: AlignmentDirectional.centerEnd,
color: Colors.red,
child: Padding(
padding: EdgeInsets.fromLTRB(0.0, 0.0, 10.0, 0.0),
),
), //ここまで追加
child: Card(
child: ListTile(
title: Text(itemList[index]),
),
),
);
ついでにアイコンも!
なんか物足りないので、最後にゴミ箱のアイコンを足してみたいと思います。
return Dismissible(
key: UniqueKey(),
direction: DismissDirection.endToStart,
background: Container(
alignment: AlignmentDirectional.centerEnd,
color: Colors.red,
child: Padding(
padding: EdgeInsets.fromLTRB(0.0, 0.0, 10.0, 0.0),
//Padding配下にchildを足し、Iconを配置
child: Icon(
Icons.delete,
color: Colors.white,
),//ここまで追加
),
),
child: Card(
child: ListTile(
title: Text(itemList[index]),
),
),
);
Paddingの配下に新しく子要素(child)を作成し、Iconを置きます。配置できるアイコンは多数が既に用意されているものなので、新しく導入する必要は殆どないでしょう。
利用可能なIconの一覧はここで確認できます。
というわけで、無事に実装完了です!せっかくですので動きを確認してみましょう。
コード全体
全体のコードは以下のようになりました。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<String> itemList = ["item1", "item2", "item3", "item4", "item5"];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
itemCount: itemList.length,
itemBuilder: (context, index) {
return Dismissible(
key: UniqueKey(),
direction: DismissDirection.endToStart,
//backgroundパラメータを追加
background: Container(
alignment: AlignmentDirectional.centerEnd,
color: Colors.red,
child: Padding(
padding: EdgeInsets.fromLTRB(0.0, 0.0, 10.0, 0.0),
child: Icon(
Icons.delete,
color: Colors.white,
),
),
),
child: Card(
child: ListTile(
title: Text(itemList[index]),
),
),
);
},
),
);
}
}
まとめ
- CardをDismissibleでラッピングすればとりあえずスワイプ削除は実現できる
- 方向指定はDismissible配下のdirectionで
- 背景色、アイコンも設定できるよ!