Hero
π¬ νλ©΄ μ νμ μμ°μ€λ½κ² μ°κ²°λλ μ λλ©μ΄μ μ μ§μ
π¬ μ΄μ νλ©΄μΌλ‘ λμκ° λλ μμ°μ€λ½κ² μ λλ©μ΄μ μ΄ λμνλ€.
π¬ μ λλ©μ΄μ ν¨κ³Όμ λμμ΄ λλ μμͺ½ νλ©΄μ μμ ―μ Hero μμ ―μΌλ‘ κ°μΈκ³ , tag νλ‘νΌν°λ₯Ό λ°λμ λμΌνκ² μ§μ ν΄μΌ νλ€.
// 첫 λ²μ§Έ νμ΄μ§
class HeroPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Hero'),
),
body: Center(
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HeroDetailPage()),
);
},
child: Hero(
tag: 'image', // μ¬κΈ°μ μμ±ν νκ·Έμ λ λ²μ§Έ νκ·Έκ° λμΌν΄μΌ ν¨
child: Image.asset(
'assets/sample.jpg',
width: 100,
height: 100,
),
),
),
),
);
}
}
// λ λ²μ§Έ νμ΄μ§
class HeroDetailPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Hero Detail'),
),
body: Hero(
tag: 'image', // μ¬κΈ°μ μμ±ν νκ·Έμ 첫 λ²μ§Έ νκ·Έκ° λμΌν΄μΌ ν¨
child: Image.asset('assets/sample.jpg'),
),
);
}
}
AnimatedContainer
π¬ ν νλ©΄ λ΄μμ setState() ν¨μλ₯Ό νΈμΆνμ¬ νλ©΄μ μλ‘ κ·Έλ¦΄ λ λ³κ²½λ νλ‘νΌν°μ μν΄ μ λλ©μ΄μ λλ€.
π¬ μνλ₯Ό λ³κ²½μν€λ©΄μ μ λλ©μ΄μ μ΄ μ μ©λλ―λ‘ StatefulWidgetμΌλ‘ μμ±νλ€.
AnimatedContainer(
duration: Duration(seconds: 1), // 1μ΄ λμ μ λλ©μ΄μ
μ μ©
width: 100.0, // κ°λ‘ κΈΈμ΄
height: 150.0, // μΈλ‘ κΈΈμ΄
child: [μμ ―],
curve: Curves.fastoutSlowIn, // 미리 μ μλ μ λλ©μ΄μ
ν¨κ³Ό
),
π¬ 100 x 100 ν¬κΈ°μ μ΄λ―Έμ§λ₯Ό ννλ©΄ 100 ~ 299 ν¬κΈ°λ‘ λλ€νκ² ν¬κΈ°κ° λ³κ²½λμ΄ μ λλ©μ΄μ λλ μμ
import 'dart:math'; // Random ν΄λμ€ μ¬μ©μ νμ
...
class _AnimatedContainerPageState extends State<AnimatedContainerPage> {
var _size = 100.0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('AnimatedContainer'),
),
body: Center(
child: GestureDetector(
onTap: () {
final random = Random(); // Random ν΄λμ€ μ¬μ© μ€λΉ
setState(() {
// ν΄λ¦ν λλ§λ€ 100.0~299.0 μ¬μ΄μ μ€μλ₯Ό λλ€νκ² μ»κΈ°
_size = random.nextInt(200).toDouble() + 100;
});
},
child: AnimatedContainer(
duration: Duration(seconds: 1),
width: _size, // λλ€ν κ°μ μ μ©
height: _size, // λλ€ν κ°μ μ μ©
child: Image.asset('assets/sample.jpg'),
curve: Curves.fastOutSlowIn,
),
),
),
);
}
}
β« setState() ν¨μμ μν΄ λ€μ κ·Έλ €μ§ λ AnimatedContainer μμ ―μ μ΄μ _size κ°μμ μλ‘ κ°±μ λ _size κ°κΉμ§ 1μ΄ λμ fastOutSlowInμ μ μλ ν¨κ³Όκ° μ μ©λλ©° μ λλ©μ΄μ λλ€.
SliverAppBarμ SliverFillRemaining
π¬ SliverAppBarμ SliverFillRemainingμ νλ©΄ ν€λλ₯Ό λμ μΌλ‘ νννλ μμ ―μ΄λ€.
π¬ ν€λλ₯Ό μλ‘ μ€ν¬λ‘€νλ©΄ ν€λ λΆλΆμ΄ μμμ§λ©΄μ ν€λ νλ¨μ μλ μ μ μΈ λ΄μ©λ§ 보μ΄λ AppBar ννλ‘ μ λλ©μ΄μ λλ©°, μ΄λ¬ν ν¨κ³Όλ₯Ό Sliver ν¨κ³ΌλΌκ³ νλ€.
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar( // ν€λ μμ
pinned: true, // μΆμμ μλ¨μ AppBarκ° κ³ μ λλμ§ μ€μ
expandedHeight: 180.0, // ν€λμ μ΅λ λμ΄
flexibleSpace: FlexibleSpaceBar( // λμ΄λλ μμμ UI μ μ
title: Text('Sliver'),
background: Image.asset(
'assets/sample.jpg',
fit: BoxFit.cover,
),
),
),
SliverFillRemaining( // λ΄μ© μμ
child: Center(
child: Text('center'),
),
),
],
),
);
}
β« Scaffoldμ appBarλ₯Ό μ§μ νμ§ μκ³ bodyμ CustomScrollViewμ μΈμ€ν΄μ€λ₯Ό μ§μ νλ€.
β« CustomScrollViewμ slivers νλ‘νΌν°μ SliverAppBarμ SliverFillRemaining μμ ―μ μ€μ νλ€.
β« SliverAppBar μμ ―μ Sliver ν¨κ³Όλ₯Ό μν μ΅μνμ νλ‘νΌν°
β« pinned : μΆμλ λ μλ¨μ AppBarκ° κ³ μ λ μ§ μ¬λΌμ§μ§ μ€μ νλ€.
β« expandedHeight : νλλ λμ μ΅λ λμ΄λ₯Ό μ νλ€.
β« flexibleSpace : νλ/μΆμλλ μμμ UIλ₯Ό μμ±νλ€.
β« flexibleSpace μμ ―μ titleκ³Ό background νλ‘νΌν°λ₯Ό νμ©νμ¬ μ μ ν AppBar μμμ΄ νμ₯λμμ λμ UIλ₯Ό μμ±νλ€.
β« SliverFillRemaining μμ ―μλ μ€ν¬λ‘€ μμμ νμλ νλ©΄μ μ μνλ€.
β« childμ μμ±ν λ΄μ©μ ν¬κΈ°κ° μμλ SliverAppBar λΆλΆμ΄ μΆμλ λ λ± νλμ ν¬κΈ°κ° μμμ κ²°μ λλ€.
SliverAppBarμ SliverList
π¬ ListViewλ₯Ό μ¬μ©νμ¬ Sliver ν¨κ³Όλ₯Ό μ£Όκ³ μΆλ€λ©΄, ListView λμ SliverListλ₯Ό μ¬μ©ν΄μΌ νλ€.
// 'No.0'μμ 'No.49'κΉμ§ νμνλ ListTileμ λ΄μ 리μ€νΈ
final _items = List.generate(50, (i) => ListTile(title: Text('No.$i')));
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
pinned: true,
expandedHeight: 180.0,
flexibleSpace: FlexibleSpaceBar(
title: Text('Sliver'),
background: Image.asset(
'assets/sample.jpg',
fit: BoxFit.cover,
),
),
),
SliverList(
// μμ±μμ νμν μμ ― 리μ€νΈ(_items)λ₯Ό μΈμλ‘ μ λ¬
delegate: SliverChildListDelegate(_items),
),
],
),
);
}
Staggered Animations
π¬ μμ ―μ Opacity, Width, Height, Padding, BorderRadius, Color λ±μ μ΄μ κ°κ³Ό μ΄ν κ°μΌλ‘ intervalμ λ§μΆ°μ λ³κ²½νλ μ λλ©μ΄μ
ꡬνλΆ
import 'package:flutter/material.dart';
class StaggerAnimation extends StatelessWidget {
StaggerAnimation({Key? key, required this.controller})
:
opacity = Tween<double>(
begin: 0.0, // μ λλ©μ΄μ
μμ
end: 1.0, // μ λλ©μ΄μ
λ
).animate(
CurvedAnimation(
parent: controller,
curve: const Interval( // 0μμ 1κΉμ§ μ λλ©μ΄μ
μ μ© μμ
0.0,
0.100,
curve: Curves.ease,
),
),
),
width = Tween<double>(
begin: 50.0,
end: 150.0,
).animate(
CurvedAnimation(
parent: controller,
curve: const Interval(
0.125,
0.250,
curve: Curves.ease,
),
),
),
height = Tween<double>(begin: 50.0, end: 150.0).animate(
CurvedAnimation(
parent: controller,
curve: const Interval(
0.250,
0.375,
curve: Curves.ease,
),
),
),
padding = EdgeInsetsTween(
begin: const EdgeInsets.only(bottom: 16.0),
end: const EdgeInsets.only(bottom: 75.0),
).animate(
CurvedAnimation(
parent: controller,
curve: const Interval(
0.250,
0.375,
curve: Curves.ease,
),
),
),
borderRadius = BorderRadiusTween(
begin: BorderRadius.circular(4.0),
end: BorderRadius.circular(75.0),
).animate(
CurvedAnimation(
parent: controller,
curve: const Interval(
0.375,
0.500,
curve: Curves.ease,
),
),
),
color = ColorTween(
begin: Colors.indigo[100],
end: Colors.orange[400],
).animate(
CurvedAnimation(
parent: controller,
curve: const Interval(
0.500,
0.750,
curve: Curves.ease,
),
),
),
super(key: key);
final Animation<double> controller;
final Animation<double> opacity;
final Animation<double> width;
final Animation<double> height;
final Animation<EdgeInsets> padding;
final Animation<BorderRadius?> borderRadius;
final Animation<Color?> color;
Widget _buildAnimation(BuildContext context, Widget? child) {
return Container(
padding: padding.value, // μ λλ©μ΄μ
μ μ©
alignment: Alignment.bottomCenter,
child: Opacity(
opacity: opacity.value, // μ λλ©μ΄μ
μ μ©
child: Container(
width: width.value, // μ λλ©μ΄μ
μ μ©
height: height.value, // μ λλ©μ΄μ
μ μ©
decoration: BoxDecoration(
color: color.value, // μ λλ©μ΄μ
μ μ©
border: Border.all(
color: Colors.indigo[300]!,
width: 3.0,
),
borderRadius: borderRadius.value, // μ λλ©μ΄μ
μ μ©
),
),
),
);
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
builder: _buildAnimation,
animation: controller,
);
}
}
μ€νλΆ
import 'dart:async';
import 'package:flutter/scheduler.dart' show timeDilation;
class StaggerDemo extends StatefulWidget {
const StaggerDemo({Key? key}) : super(key: key);
@override
_StaggerDemoState createState() => _StaggerDemoState();
}
class _StaggerDemoState extends State<StaggerDemo>
with TickerProviderStateMixin {
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 2000), vsync: this);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
Future<void> _playAnimation() async {
try {
await _controller.forward().orCancel; // μ λλ©μ΄μ
μ λ°©ν₯ μ€ν
await _controller.reverse().orCancel; // μ λλ©μ΄μ
μλ°©ν₯ μ€ν
} on TickerCanceled {
// the animation got canceled, probably because we were disposed
}
}
@override
Widget build(BuildContext context) {
timeDilation = 10.0; // 1.0 is normal animation speed.
return Scaffold(
appBar: AppBar(
title: const Text('Staggered Animation'),
),
body: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
_playAnimation();
},
child: Center(
child: Container(
width: 300.0,
height: 300.0,
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.1),
border: Border.all(
color: Colors.black.withOpacity(0.5),
),
),
// μ λλ©μ΄μ
μ μ© : μ λλ©μ΄μ
+ μμ ―
child: StaggerAnimation(controller: _controller.view),
),
),
),
);
}
}
void main() {
runApp(
const MaterialApp(
home: StaggerDemo(),
),
);
}
'Flutter > Concept' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
[ Flutter ] νλ©΄ μ΄λ (0) | 2021.12.29 |
---|---|
[ Flutter ] μΏ νΌν°λ Έ λμμΈ (0) | 2021.12.29 |
[ Flutter ] λ€μ΄μΌλ‘κ·Έ (0) | 2021.12.29 |
[ Flutter ] λ²νΌ (0) | 2021.12.28 |
[ Flutter ] νλ©΄ λ°°μΉ (0) | 2021.12.28 |