// 이곳에 쓴 내용은 앱 만들기라는 버킷리스트를 달성하기 위해 플러터를 공부하면서 정리하고 있는 내용입니다.
플러터에 대해 아는 것이 거의 없기 때문에 정리하면서 오류가 있을 수 있습니다.
오류를 발견하신 분은 댓글 남겨 주시면 감사하겠습니다.
애니메이션 구현하기
https://api.flutter.dev/flutter/animation/Curves-class.html
https://flutter-gallery-archive.web.app/
구글 스토어에서 앱을 다운 받을 수 있다는데 못 찾겠다. 웹으로 확인 가능하지만 뭘 확인해야 할지는 모르겠다.^^;;
오늘도 열심히 타자 연습을 했다.
눈이 빠지겠다. 어떤 순서가 있지만 그 순서들을 무시하고 타이핑을 했더니만 어떤 작동 원리인지는 잘 모르겠다.
그냥 이런 기능이 있구나 정도만 파악하고 있다.ㅜ.ㅜ
도대체 왜 state를 작성할 때 introPage 이딴 식으로 쓰는 걸까? 왜 가운데 글자를 대문자로 써야 하는거지?
이유가 없다면 정말 짜증이 난다. 이걸 찾으려고 도대체 몇 개의 다트 파일을 훑어 보고 또 봤는지..ㅜ.ㅜ
pubspec.yaml에 image 3개를 등록하고, 코드를 복사?했다. 이번에는 무조건 따라 쳤다. 무슨 의미냐면 stless를 치면 나오면 state 지정하는 문구 등을 그냥 똑같이 쳤고, 줄도 똑같이 했다. 그래야 오류 부분을 쉽게 찾을 수가 있어서..
그럼, 오늘의 타이핑 확인?
main.dart
import 'package:flutter/material.dart';
import 'intro.dart';
import 'people.dart';
import 'secondPage.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
),
home: const IntroPage(),
);
}
}
class AnimationApp extends StatefulWidget {
@override
State<StatefulWidget> createState() => _AnimationApp();
}
class _AnimationApp extends State<AnimationApp>{
List<People> peoples = List.empty(growable: true);
int current = 0;
Color weightColor = Colors.blue;
double _opacity = 1;
@override
void initState(){
peoples.add(People('스미스', 180, 92));
peoples.add(People('메리', 162, 55));
peoples.add(People('존', 177, 75));
peoples.add(People('바트', 130, 40));
peoples.add(People('콘', 194, 140));
peoples.add(People('디디', 100, 80));
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Animatioin Example'),
),
body: Container(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
AnimatedOpacity(
opacity: _opacity,
duration: const Duration(seconds: 1),
child:
SizedBox(
height: 200,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
SizedBox(width:100, child: Text('이름: ${peoples[current].name}')),
AnimatedContainer(
duration: const Duration(seconds: 2),
curve: Curves.bounceIn,
color: Colors.amber,
width: 50,
height: peoples[current].height,
child: Text(
'키${peoples[current].height}',
textAlign: TextAlign.center,
),
),
AnimatedContainer(
duration: const Duration(seconds: 2),
curve: Curves.easeInCubic,
color: weightColor,
width: 50,
height: peoples[current].weight,
child: Text(
'몸무게${peoples[current].weight}',
textAlign: TextAlign.center,
),
),
AnimatedContainer(
duration: const Duration(seconds: 2),
curve: Curves.linear,
color: Colors.pinkAccent,
width: 50,
height: peoples[current].bmi,
child: Text(
'bmi${peoples[current].bmi}',
textAlign: TextAlign.center,
),
)
],
),
),
),
ElevatedButton(
onPressed: (){
setState((){
if (current < peoples.length - 1){
current++;
}
_changeWeightColor(peoples[current].weight);
});
},
child: const Text('다음'),
),
ElevatedButton(
onPressed: () {
setState((){
if (current > 0){
current--;
}
_changeWeightColor(peoples[current].weight);
});
},
child: const Text('이전'),
),
ElevatedButton(onPressed: () {
setState((){
_opacity == 1? _opacity = 0 : _opacity = 1;
});
},
child: const Text('사라지기'),
),
ElevatedButton(
onPressed: (){
Navigator.of(context).push(MaterialPageRoute(builder:
(context)=> SecondPage()));
},
child: SizedBox(
width: 200,
child: Row(
children: const <Widget>[
Hero(tag: 'detail', child: Icon(Icons.cake)),
Text('이동하기')
],
),
),),
],),),),
);
}
void _changeWeightColor(double weight){
if (weight < 40) {
weightColor = Colors.blueAccent;
} else if (weight < 60){
weightColor = Colors.indigo;
} else if (weight < 80){
weightColor = Colors.orange;
} else {
weightColor = Colors.red;
}
}
}
intro.dart
import 'package:doit11_1/main.dart';
import 'package:flutter/material.dart';
import 'package:doit11_1/saturnLoading.dart';
import 'dart:async';
class IntroPage extends StatefulWidget {
const IntroPage({super.key});
@override
State<StatefulWidget> createState() => _IntroPage();
}
class _IntroPage extends State<IntroPage> {
@override
void initState() {
super.initState();
loadData();
}
Future<Timer> loadData() async {
return Timer(const Duration(seconds: 5), onDoneLoading);
}
onDoneLoading() async {
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (context) => AnimationApp()));
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('애니메이션 앱'),
const SizedBox(
height: 20,
),
SaturnLoading()
],
),),);
}
}
people.dart
class People{
String name;
double height;
double weight;
double? bmi;
People(this.name, this.height, this.weight){
bmi = weight / ((height/100)*(height/100));
}
}
saturnLoading.dart
import 'package:flutter/material.dart';
import 'dart:math';
class SaturnLoading extends StatefulWidget {
final _SaturnLoading _saturnLoading = _SaturnLoading();
SaturnLoading({super.key});
void start(){
_saturnLoading.start();
}
void stop(){
_saturnLoading.stop();
}
@override
State<StatefulWidget> createState() => _SaturnLoading();
}
class _SaturnLoading extends State<SaturnLoading>
with SingleTickerProviderStateMixin {
AnimationController? _animationController;
Animation? _animation;
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _animationController!,
builder: (context, child){
return SizedBox(
width: 100,
height: 100,
child: Stack(
children: <Widget>[
Image.asset(
'repo/images/circle.png',
width: 100,
height: 100,
),
Center(
child: Image.asset(
'repo/images/sunny.png',
width: 30,
height: 30,
),
),
Padding(
padding: const EdgeInsets.all(5),
child: Transform.rotate(
angle: _animation!.value,
origin: const Offset(35, 35),
child: Image.asset(
'repo/images/saturn.png',
width: 20,
height: 20,
),),)
],),);
},);
}
void stop(){
_animationController!.stop(canceled: true);
}
void start(){
_animationController!.repeat();
}
@override
void initState(){
super.initState();
_animationController=
AnimationController(vsync: this, duration: const Duration(seconds: 3));
_animation =
Tween<double>(begin: 0, end: pi * 2).animate(_animationController!);
_animationController!.repeat();
}
@override
void dispose(){
_animationController!.dispose();
super.dispose();
}
}
secondPage.dart
import 'package:flutter/material.dart';
import 'dart:math';
class SecondPage extends StatefulWidget {
const SecondPage({super.key});
@override
State<StatefulWidget> createState() => _SecondPage();
}
class _SecondPage extends State<SecondPage>
with SingleTickerProviderStateMixin {
AnimationController? _animationController;
Animation? _rotateAnimation;
Animation? _scaleAnimation;
Animation? _transAnimation;
@override
void initState() {
super.initState();
_animationController =
AnimationController(duration: const Duration(seconds: 5), vsync: this);
_rotateAnimation =
Tween<double>(begin: 0, end: pi * 10).animate(_animationController!);
_scaleAnimation =
Tween<double>(begin: 1, end: 0).animate(_animationController!);
_transAnimation =
Tween<Offset>(begin: const Offset(0, 0), end: const Offset(200, 200))
.animate(_animationController!);
}
@override
void dispose() {
_animationController!.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Animation Example2'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
AnimatedBuilder(
animation: _rotateAnimation!,
builder: (context, widget) {
return Transform.translate(
offset: _transAnimation!.value,
child: Transform.rotate(
angle: _rotateAnimation!.value,
child: Transform.scale(
scale: _scaleAnimation!.value,
child: widget,
)),
);
},
child: const Hero(
tag: 'detail',
child: Icon(
Icons.cake,
size: 300,
)),
),
ElevatedButton(
onPressed: () {
_animationController!.forward();
},
child: const Text('로테이션 시작하기'),
),
],
),
),
);
}
}
sliverPage.dart
import 'package:flutter/material.dart';
import 'dart:math' as math;
class SliverPage extends StatefulWidget {
const SliverPage({super.key});
@override
State<StatefulWidget> createState() => _SliverPage();
}
class _SliverPage extends State<SliverPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
pinned: true,
expandedHeight: 150,
flexibleSpace: FlexibleSpaceBar(
title: const Text('Sliver Example'),
background: Image.asset('repo/image/sunny.png'),
),
backgroundColor: Colors.deepOrangeAccent,
),
SliverPersistentHeader(
delegate: _HeaderDelegate(
minHeight: 50,
maxHeight: 150,
child: Container(
color: Colors.blue,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
Text(
'list 숫자',
style: TextStyle(fontSize: 30),
),
],
),
),
)),
pinned: true,
),
SliverList(
delegate: SliverChildListDelegate([
customCard('1'),
customCard('2'),
customCard('3'),
customCard('4'),
])),
SliverPersistentHeader(
delegate: _HeaderDelegate(
minHeight: 50,
maxHeight: 150,
child: Container(
color: Colors.blue,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const<Widget>[
Text(
'그리드 숫자',
style: TextStyle(fontSize: 30),
),
],
),
),
)),
pinned: true,
),
SliverGrid(
delegate: SliverChildListDelegate([
customCard('1'),
customCard('2'),
customCard('3'),
customCard('4'),
]),
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:2)),
],
),
);
}
Widget customCard(String text){
return Card(
child: Container(
height: 120,
child: Center(
child: Text(
text,
style: const TextStyle(fontSize: 40),
)),
),
);
}
}
class _HeaderDelegate extends SliverPersistentHeaderDelegate {
final double minHeight;
final double maxHeight;
final Widget child;
_HeaderDelegate({
required this.minHeight,
required this.maxHeight,
required this.child,
});
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContexnt){
return SizedBox.expand(child: child);
}
@override
double get maxExtent => math.max(maxHeight, minHeight);
@override
double get minExtent => minHeight;
@override
bool shouldRebuild(_HeaderDelegate oldDelegate){
return maxHeight != oldDelegate.maxHeight ||
minHeight != oldDelegate.minHeight ||
child != oldDelegate.child;
}
}
오늘은 별다른 코멘트를 붙이고 싶지 않다. 너무 힘들었다. 타이핑하는 것만으로도..
이해는 언젠가 되겠지~^^;;
'버킷리스트 > 앱 만들기' 카테고리의 다른 글
오공완 (with Do it! 플러터 앱 프로그램밍) #13_1 (0) | 2024.05.15 |
---|---|
오공완 (with Do it! 플러터 앱 프로그램밍) #12_1 (0) | 2024.05.15 |
오공완 (with Do it! 플러터 앱 프로그램밍) #10_1 (0) | 2024.05.12 |
오공완 (with Do it! 플러터 앱 프로그램밍) #9_2 (0) | 2024.05.12 |
오공완 (with Do it! 플러터 앱 프로그램밍) #9_1 (0) | 2024.05.10 |