はじめに
前回はFlutter Widget of the Weekの「#1 SafeArea」、「#2 Expanded」を紹介しました。
今回はその続きで「#3 Wrap」、「#4 AnimatedContainer」、「#5 Opacity」の3つです。
前回の記事はこちら
またコードはGitHubに公開していますので見たい方は自由に使ってください。
Flutter Widget of the Week
環境
- Flutter 2.5.3
記事にした時点でのバージョンです。GitHubに公開しているのは常に最新の安定版(stable)を使う予定です。
#3 Wrap
Wrapとは
ウィジェットをレイアウトする時にはRowとColumnをよく使いますが、スペース不足になる場合があります。
この問題を解決してくれるのがWrapウィジェットです。
WrapはRowやColumnのように子ウィジェットを順番に配置しますが、縦や横のスペースがなくなった場合は改行(wrap)してくれます。
またdirectionプロパティを使うことで縦横どちらの方向に改行(wrap)するのか設定できます。
alignmentプロパティやspacingプロパティもあります。
WrapはダイアログのボタンやChip系のウィジェットと組み合わせると良いそうです。
サンプルコード
import 'package:flutter/material.dart';
class SamplePage003 extends StatelessWidget {
const SamplePage003({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Wrap'),
),
body: SafeArea(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Row'),
Container(
color: Colors.lightBlue,
child: Row(
children: const [
_SamplePage003Child(),
_SamplePage003Child(),
_SamplePage003Child(),
_SamplePage003Child(),
],
),
),
const SizedBox(height: 30),
const Text('Wrap'),
Container(
color: Colors.lightBlue,
child: Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.center,
spacing: 10,
runSpacing: 10,
children: const [
_SamplePage003Child(),
_SamplePage003Child(),
_SamplePage003Child(),
_SamplePage003Child(),
],
),
),
],
),
),
),
);
}
}
class _SamplePage003Child extends StatelessWidget {
const _SamplePage003Child();
@override
Widget build(BuildContext context) {
return Container(
width: 100,
height: 100,
color: Colors.red,
);
}
}
結果
Rowを使った場合は「A RenderFlex overflowed by 10.0 pixels on the right.」というエラーが出ますが、Wrapを使った場合は自動で改行してくれています。
動画
公式リファレンス
#4 AnimatedContainer
AnimatedContainerとは
Flutterには開発者が自分でコーディングする明示的アニメーション用のウィジェットが沢山ありますが
自動で変化する暗示的アニメーションウィジェットもあります。
暗示的アニメーションに便利なのがAnimatedContainerウィジェットです。
色などの属性を加えて一度作成するだけで簡単に使えます。
例えばsetStateの呼び出しに対応させる形で値を書き換えクラスをビルドさせると
AnimatedContainerがその二つの値の線形補間を行います。
colorだけでなく、border,border radius,background,images,shadows,gradients,shapes,padding,width,height,alignment,transformsなど色々なプロパチhあります。
アニメーションの長さはdurationプロパティで変更し、Curveを設定するとエフェクトをカスタマイズすることも出来ます。
サンプルコード
import 'package:flutter/material.dart';
class SamplePage004 extends StatefulWidget {
const SamplePage004({
Key? key,
}) : super(key: key);
@override
_SamplePage004State createState() => _SamplePage004State();
}
class _SamplePage004State extends State<SamplePage004> {
bool toggle = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('AnimatedContainer'),
),
body: SafeArea(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Container'),
Container(
color: toggle ? Colors.red : Colors.blue,
width: toggle ? 100 : 150,
height: 150,
child: const Icon(
Icons.face,
color: Colors.white,
),
),
const SizedBox(height: 50),
const Text('AnimatedContainer'),
AnimatedContainer(
duration: const Duration(milliseconds: 500),
curve: Curves.easeIn,
color: toggle ? Colors.red : Colors.blue,
width: toggle ? 100 : 150,
height: 150,
child: const Icon(
Icons.face,
color: Colors.white,
),
),
],
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
toggle = !toggle;
});
},
child: const Icon(Icons.change_circle),
),
);
}
}
結果
Containerの場合、パッと切り替わるのに対して、AnimatedContainerだとアニメーションしながらキレイに切り替わりました。
動画
公式リファレンス
#5 Opacity
Opacityとは
ウィジェット削除する場合はウィジェットなしでビルドし直すだけです。
しかしウィジェットを非表示にしても領域を確保し、他のレイアウトを保ちたい場合にはOpacityウィジェットを使います。
ウィジェットをOpacityで囲んでopacityプロパティの値を0に設定するだけです。
またOpacityを使ってStackの子を重ねて一体化することができます。
表示変化をアニメーションさせたければAnimatedOpacityを使います
durationとopacityプロパティを設定して、ビルドし直せば自動的にアニメーションします。
サンプルコード
import 'package:flutter/material.dart';
class SamplePage005 extends StatefulWidget {
const SamplePage005({Key? key}) : super(key: key);
@override
_SamplePage005State createState() => _SamplePage005State();
}
class _SamplePage005State extends State<SamplePage005> {
bool toggle = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Opacity'),
),
body: SafeArea(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Opacityなし'),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const _SamplePage005Child(),
if (!toggle) const _SamplePage005Child(),
const _SamplePage005Child(),
],
),
const Text('Opacityあり'),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const _SamplePage005Child(),
Opacity(
opacity: toggle ? 0 : 1,
child: const _SamplePage005Child(
color: Colors.red,
),
),
const _SamplePage005Child(),
],
),
const Text('Stackを利用したサンプル(AnimatedOpacity)'),
Stack(
children: [
const FlutterLogo(
size: 100,
),
AnimatedOpacity(
opacity: toggle ? 1 : 0,
duration: const Duration(milliseconds: 500),
child: const _SamplePage005Child(),
),
],
),
],
),
),
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.change_circle),
onPressed: () {
setState(() {
toggle = !toggle;
});
},
),
);
}
}
class _SamplePage005Child extends StatelessWidget {
const _SamplePage005Child({
this.color = Colors.blue,
});
final Color color;
@override
Widget build(BuildContext context) {
return Container(
width: 100,
height: 100,
color: color,
);
}
}
結果
Opacityなしの場合は青色ウィジェットのレイアウトが変わってしまいますが、Opacityありだと変わらずにすることができます。
またAnimatedOpacity使うことで画像のフェードを再現することもできそうです。
動画
公式リファレンス
さいごに
使ったことのないWidgetがあると新しい発見があって楽しい。
コメント