はじめに
前回はFlutter Widget of the Weekの「#28 Dismissible」、「#29 SizedBox」、「#30 ValueListenableBuilder」を紹介しました。
今回はその続きで「#31 Draggable」、「#32 AnimatedList」、「#33 Flexible」の3つです。
前回の記事はこちら
Flutter Widget of the Week
環境
- Flutter 2.10.3
記事にした時点でのバージョンです。GitHubに公開しているのは常に最新の安定版(stable)を使う予定です。
#31 Draggable
Draggableとは
ドラッグ&ドロップを実現するためのウィジェットです。
Draggableがドラッグする対象の設定で、ドロップする場所はDragTargetウィジェットを利用します。
サンプルコード
import 'package:flutter/material.dart';
class SamplePage031 extends StatefulWidget {
const SamplePage031({
Key? key,
}) : super(key: key);
@override
State<SamplePage031> createState() => _SamplePage031State();
}
class _SamplePage031State extends State<SamplePage031> {
Color _selectedColor = Colors.white;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Draggable'),
centerTitle: true,
),
body: SafeArea(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: double.infinity,
height: 120,
color: Colors.grey[100],
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: const [
_SamplePage031Draggable(
color: Colors.blue,
),
_SamplePage031Draggable(
color: Colors.yellow,
),
_SamplePage031Draggable(
color: Colors.red,
),
],
),
),
Expanded(
child: Container(
color: _selectedColor,
child: Center(
child: DragTarget<Color>(
onWillAccept: (value) => value != _selectedColor,
onAccept: (value) {
setState(() {
_selectedColor = value;
});
},
builder: (context, candidates, rejects) {
return Container(
width: 100,
height: 100,
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
color: Colors.white,
),
child: const Center(
child: Text('ここに\nドラッグ'),
),
);
},
),
),
),
),
],
),
),
);
}
}
class _SamplePage031Draggable extends StatelessWidget {
const _SamplePage031Draggable({
Key? key,
this.color,
}) : super(key: key);
final Color? color;
@override
Widget build(BuildContext context) {
return Draggable<Color>(
data: color,
childWhenDragging: _SamplePage031Child(
color: color,
child: const Text('ドラッグ中'),
),
feedback: _SamplePage031Child(
color: color,
child: const Icon(Icons.face),
),
child: _SamplePage031Child(
color: color,
child: const Text('通常'),
),
);
}
}
class _SamplePage031Child extends StatelessWidget {
const _SamplePage031Child({
Key? key,
this.color,
this.child,
}) : super(key: key);
final Color? color;
final Widget? child;
@override
Widget build(BuildContext context) {
return Container(
width: 100,
height: 100,
color: color,
child: Center(child: child),
);
}
}
結果
上の3色のいずれかをドラッグして、「ここへドラッグ」でドロップすると。。。
指定した色に変化します。
動画
公式リファレンス
Draggable class - widgets library - Dart API
API docs for the Draggable class from the widgets library, for the Dart programming language.
#32 AnimatedList
AnimatedListとは
リスト表示で追加や削除時にアニメーションをさせたい場合にこのAnimatedListを使います。
サンプルコード
import 'package:flutter/material.dart';
class SamplePage032 extends StatefulWidget {
const SamplePage032({
Key? key,
}) : super(key: key);
@override
State<SamplePage032> createState() => _SamplePage032State();
}
class _SamplePage032State extends State<SamplePage032> {
final _listKey = GlobalKey<AnimatedListState>();
final _data = <String>[
'0',
'1',
'2',
'3',
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('AnimatedList'),
centerTitle: true,
),
body: SafeArea(
child: AnimatedList(
key: _listKey,
initialItemCount: _data.length,
itemBuilder: (context, index, animation) {
return _SamplePage032Item(
animation: animation,
title: Text(_data[index]),
onTap: () {
final removeIndex = index;
final removeItem = _data[index];
_SamplePage032Item builder(
BuildContext context,
Animation<double> animation,
) {
return _SamplePage032Item(
animation: animation,
title: Text(removeItem),
);
}
_data.removeAt(removeIndex);
_listKey.currentState!.removeItem(removeIndex, builder);
},
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
final index = _data.length;
_data.insert(index, index.toString());
_listKey.currentState!.insertItem(index);
});
},
child: const Icon(Icons.add),
),
);
}
}
class _SamplePage032Item extends StatelessWidget {
const _SamplePage032Item({
Key? key,
required this.animation,
this.title,
this.onTap,
}) : super(key: key);
final Animation<double> animation;
final Widget? title;
final void Function()? onTap;
@override
Widget build(BuildContext context) {
return SizeTransition(
sizeFactor: animation,
child: ListTile(
title: title,
onTap: onTap,
),
);
}
}
結果
分かりづらいですが、追加時にアニメーションしてます。
アイテムをタップすると、こちらも分かりづらいですがアニメーションしながら削除されます。
動画
公式リファレンス
AnimatedList class - widgets library - Dart API
API docs for the AnimatedList class from the widgets library, for the Dart programming language.
#33 Flexible
Flexibleとは
親ウィジェットのサイズに合わせて、相対的に大きさを変更したい場合にこのウィジェットを使います。
サンプルコード
import 'package:flutter/material.dart';
class SamplePage033 extends StatefulWidget {
const SamplePage033({
Key? key,
}) : super(key: key);
@override
State<SamplePage033> createState() => _SamplePage033State();
}
class _SamplePage033State extends State<SamplePage033> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flexible'),
centerTitle: true,
),
body: SafeArea(
child: Column(
children: [
Flexible(
flex: 2,
child: Container(
color: Colors.cyan,
child: const Center(
child: Text(
'1/3\n(2 Flex / 6 Total)',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white),
),
),
),
),
Flexible(
flex: 3,
child: Container(
color: Colors.teal,
child: const Center(
child: Text(
'1/2\n(3 Flex / 6 Total)',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white),
),
),
),
),
Flexible(
flex: 1,
child: Container(
color: Colors.indigo,
child: const Center(
child: Text(
'1/6\n(1 Flex / 6 Total)',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white),
),
),
),
),
],
),
),
);
}
}
結果
それぞれ、画面に対して割合になっています。仮に解像度が変わってもこの割合はかわりません。
動画
公式リファレンス
Flexible class - widgets library - Dart API
API docs for the Flexible class from the widgets library, for the Dart programming language.
さいごに
DraggableとFlexibleは頻繁に使いそうなのでしっかり覚えておきたいですね。
AnimatedListはワタシ的にはそこまで必要じゃなさそうですね。
おすすめ参考書
リンク
GitHub - nobushiueshi/flutter_widget_of_the_week
Contribute to nobushiueshi/flutter_widget_of_the_week development by creating an account on GitHub.
コメント