💻
[Flutter] プレビュー写真をタップするとファイルチューザーが出てきて画像を差し替えられるUIの実装例
よくあるプロフィール設定画面のような感じで、
- プロフィール画像をタップしたらファイルチューザーが出てくる
- ファイルチューザーでローカルの画像ファイルを選択するとプレビューが書き換えられる
- その後保存ボタンを押すと新しい画像がサーバーに送信される
といったUIのFlutterでの実装例をお伝えしたいと思います。
動作結果のイメージはこんな感じです。
前振りもへったくれもなく結論だけ書くと、以下のようなコードで実現できます。
class Profile extends StatefulWidget {
createState() => _ProfileState();
}
class _ProfileState extends State<Profile> {
File _imageFile;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('プロフィール画像設定'),
),
body: Builder(
builder: (BuildContext context) {
return ListView(
children: [
Container(
margin: EdgeInsets.only(top: 16.0),
child: GestureDetector(
child: Center(
child: Container(
width: 150,
height: 150,
child: _imageFile != null
? Image.file(
_imageFile,
fit: BoxFit.cover,
)
: Image.network(
'https://via.placeholder.com/150',
fit: BoxFit.cover,
),
),
),
onTap: () async {
setState(() => _imageFile = await FilePicker.getFile(type: FileType.image));
},
),
),
Container(
margin: EdgeInsets.only(top: 10.0),
child: Center(
child: RaisedButton(
child: Text('保存'),
onPressed: () {
// do something, and
Scaffold.of(context).showSnackBar(SnackBar(
content: Text('プロフィール画像を変更しました'),
));
},
),
),
),
],
);
},
),
);
}
}
コードを読んで「あーハイハイ」となった方はもう卒業で大丈夫です笑
ちょっとだけ説明を書くと、
File _imageFile;
にプレビュー中の画像ファイルの File
オブジェクトを持つようにして、そのデータの有無に応じて
_imageFile != null
? Image.file(
_imageFile,
fit: BoxFit.cover,
)
: Image.network(
'https://via.placeholder.com/150',
fit: BoxFit.cover,
),
という具合で、プレビュー中の画像ファイルを表示するかダミー画像を表示するかを切り替えています。
そして、画像を GestureDetector
でラップして onTap
を生やし、そこでファイルの選択をさせています。
onTap: () async {
setState(() => _imageFile = await FilePicker.getFile(type: FileType.image));
},
ファイルチューザーを開いてローカルのファイルを取得する処理には file_picker を使っています。
あとは Container
と Center
でラップしてサイズを 150x150
に固定しているのがポイントです。
Center()
でラップしないと
こんな感じになってしまいます。
さらに Container
でラップしないと
こんな感じで拡大されてしまいます。
この辺りのレイアウトの調整はFlutterの鬼門の一つですね。(個人的には)
あとそもそも SnackBar
を使うために Builder
でラップして context
を変えている点については
[Flutter] SnackBarを使おうとすると Scaffold.of() called with(略)と言われるときの対応
をご参照ください。
Discussion