暗黙的アニメーションは一番簡単で、一番よく使います
目次
暗黙的アニメーション Widget 一覧
- AnimatedContainer・・・サイズ、色、位置、角丸など
- AnimatedOpacity・・・透明度(フェードイン/アウト)
- AnimatedAlign・・・位置
- AnimatedPositioned・・・Stack内での位置
- AnimatedPadding・・・パディング
- AnimatedDefaultTextStyle・・・テキストスタイル
- AnimatedPhysicalModel・・・影、立体感
- AnimatedCrossFade・・・2つのWidgetを切り替え
- AnimatedSwitcher・・・Widgetの入れ替え
- AnimatedScale・・・拡大・縮小
- AnimatedRotation・・・回転
実践例1: AnimatedContainer (超重要!)
サイズと色が変わるボタン
import 'package:flutter/material.dart';
class AnimatedButtonDemo extends StatefulWidget {
@override
_AnimatedButtonDemoState createState() => _AnimatedButtonDemoState();
}
class _AnimatedButtonDemoState extends State<AnimatedButtonDemo> {
bool _isExpanded = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('AnimatedContainer')),
body: Center(
child: GestureDetector(
onTap: () {
setState(() {
_isExpanded = !_isExpanded; // 状態を切り替え
});
},
child: AnimatedContainer(
// ========================================
// ここが自動でアニメーションする!
// ========================================
width: _isExpanded ? 200 : 100, // 幅が変わる
height: _isExpanded ? 200 : 100, // 高さが変わる
color: _isExpanded ? Colors.blue : Colors.red, // 色が変わる
// アニメーションの設定
duration: Duration(milliseconds: 300), // 0.3秒かけて変化
curve: Curves.easeInOut, // 変化の仕方(イージング)
child: Center(
child: Text(
'タップ!',
style: TextStyle(color: Colors.white),
),
),
),
),
),
);
}
}
たったこれだけ! ✨
動き:
タップ → サイズが大きくなる + 赤→青
もう一度タップ → サイズが小さくなる + 青→赤
AnimatedContainer でできること全部!
AnimatedContainer(
// サイズ
width: _isExpanded ? 200 : 100,
height: _isExpanded ? 200 : 100,
// 色
color: _isExpanded ? Colors.blue : Colors.red,
// 角丸
decoration: BoxDecoration(
color: _isExpanded ? Colors.blue : Colors.red,
borderRadius: BorderRadius.circular(_isExpanded ? 50 : 10),
boxShadow: _isExpanded
? [BoxShadow(color: Colors.black26, blurRadius: 10)]
: [],
),
// パディング
padding: EdgeInsets.all(_isExpanded ? 40 : 20),
// マージン
margin: EdgeInsets.all(_isExpanded ? 20 : 50),
// 位置(Alignment)
alignment: _isExpanded ? Alignment.center : Alignment.topLeft,
// トランスフォーム(回転・拡大など)
transform: _isExpanded
? Matrix4.rotationZ(0.1)
: Matrix4.rotationZ(0),
// アニメーション設定
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
child: Text('Hello'),
)
ほぼ全部アニメーションできる!
実践例2: AnimatedOpacity (フェード)
じわ〜っと消える・現れる
class FadeDemo extends StatefulWidget {
@override
_FadeDemoState createState() => _FadeDemoState();
}
class _FadeDemoState extends State<FadeDemo> {
bool _isVisible = true;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Fade Animation')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// ========================================
// 透明度がアニメーション
// ========================================
AnimatedOpacity(
opacity: _isVisible ? 1.0 : 0.0, // 1.0=表示, 0.0=透明
duration: Duration(milliseconds: 500),
child: Container(
width: 200,
height: 200,
color: Colors.blue,
child: Center(
child: Text(
'Hello',
style: TextStyle(color: Colors.white, fontSize: 30),
),
),
),
),
SizedBox(height: 40),
ElevatedButton(
onPressed: () {
setState(() {
_isVisible = !_isVisible;
});
},
child: Text(_isVisible ? '消す' : '表示'),
),
],
),
),
);
}
}
使い道:
ローディング完了後に表示
エラーメッセージを徐々に表示
要素をフェードアウトで削除
実践例3: AnimatedAlign (位置移動)
左右に動く
class SlideDemo extends StatefulWidget {
@override
_SlideDemoState createState() => _SlideDemoState();
}
class _SlideDemoState extends State<SlideDemo> {
bool _isLeft = true;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Slide Animation')),
body: Column(
children: [
Expanded(
child: AnimatedAlign(
alignment: _isLeft ? Alignment.centerLeft : Alignment.centerRight,
duration: Duration(milliseconds: 500),
curve: Curves.easeInOut,
child: Container(
width: 100,
height: 100,
color: Colors.red,
child: Center(child: Text('🚗', style: TextStyle(fontSize: 40))),
),
),
),
ElevatedButton(
onPressed: () {
setState(() {
_isLeft = !_isLeft;
});
},
child: Text('移動'),
),
SizedBox(height: 20),
],
),
);
}
}
動き: 車が左右にスライド!
実践例4: AnimatedSwitcher (切り替え)
カウンターの数字が滑らかに変わる
class CounterDemo extends StatefulWidget {
@override
_CounterDemoState createState() => _CounterDemoState();
}
class _CounterDemoState extends State<CounterDemo> {
int _counter = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Counter Animation')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// ========================================
// 数字が変わるときにアニメーション
// ========================================
AnimatedSwitcher(
duration: Duration(milliseconds: 300),
transitionBuilder: (child, animation) {
return ScaleTransition(
scale: animation,
child: child,
);
},
child: Text(
'$_counter',
key: ValueKey<int>(_counter), // keyが重要!
style: TextStyle(fontSize: 80, fontWeight: FontWeight.bold),
),
),
SizedBox(height: 40),
ElevatedButton(
onPressed: () {
setState(() {
_counter++;
});
},
child: Text('増やす'),
),
],
),
),
);
}
}
動き: 数字がポップアップで変わる! ✨
アニメーションの設定
AnimatedContainer(
duration: Duration(milliseconds: 300), // 0.3秒
// duration: Duration(seconds: 1), // 1秒
// duration: Duration(milliseconds: 100), // 0.1秒(速い)
)
目安:
100-200ms: 速い、クイックな反応
300ms: 標準、ちょうど良い ⭐
500-1000ms: ゆっくり、目立つ
curve (変化の仕方)
AnimatedContainer(
curve: Curves.easeInOut, // なめらか
)
主なカーブ:
linear 一定速度・・・・・・・・・シンプル
easeIn ゆっくり→速く・・・・・・表示開始
easeOut 速く→ゆっくり・・・・・・表示終了
easeInOut ゆっくり→速く→ゆっくり・・・万能! ⭐
bounceIn バウンド・・・・・・楽しい
elasticOut びよーん・・・・・・目立つ
おすすめ: Curves.easeInOut が一番自然! 😊
まとめ: 暗黙的アニメーション
| Widget | 用途 | 難易度 |
|---|---|---|
| AnimatedContainer | 万能! サイズ・色・位置 | ⭐ |
| AnimatedOpacity | フェードイン/アウト | ⭐ |
| AnimatedAlign | 位置移動 | ⭐ |
| AnimatedSwitcher | 切り替え | ⭐⭐ |
一言まとめ:
暗黙的アニメーションは超簡単!
AnimatedContainer でサイズ・色・位置が自動アニメーション。
AnimatedOpacity でフェード。
duration は 300ms、
curve は easeInOut が標準。
setState で値を変えるだけで自動的に滑らかに変化! 🎨✨
