반응형
Nomad Coders님의 Flutter 강의를 듣고 요약한 내용입니다. 링크는 아래와 같습니다.
해당 강의는 현재 무료로 이용할 수 있습니다.
https://nomadcoders.co/flutter-for-beginners
Flutter를 처음 공부한다면 이전 글 요약부터 보고 오시는 걸 추천드립니다.
2024.01.09 - [개발] - [Nomad Coders] Flutter 를 위한 DART 문법 요약
Hello flutter
import 'package:flutter/material.dart';
void main(){
runApp(App());
}
//App 클래스는 여기서 root 역할을 한다.
class App extends StatelessWidget{
@override // 부모클래스에 있는 그러니까 원래 StatelessWidget에 있는 build 메소드를 가져다 쓴다.
Widget build(BuildContext context){//context는 나중에 설명
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Hello flutter!'),
),
body: Center(
child: Text('Hello world!'),
)
),
);
}
}
- flutter 공식 사이트에서 각종 위젯들을 사용할 수 있다. 위젯 종류가 다양하여 원할 때 보고 사용하면 된다.
- 위젯을 만드는 것을 클래스를 만드는 것과 같다. 단순히 클래스를 만드는 것은 아니고 extends를 이용해 3가지 위젯의 종류 중 하나를 상속받아야 위젯이 된다. 여기서는 StatelessWidget을 상속받았다.
- 위젯을 만들고 싶다면 build 메소드가 필요하다.
- 모든 것의 시초가 되는 root widget은 둘 중에 하나를 return 해야만 한다. material을 리턴하면 구글 형태로 , cupertino를 리턴하면 ios 형태로 위젯이 리턴된다. 어떤 family 스타일을 설정할지 보여주는 것이다.
- MaterialApp의 프로퍼티에는 home이라는 위젯이 있다. 그래서 hello wolrd 라는 text 위젯을 부여한 것이다.
- Scaffold는 화면 구조이다.
- VS studio 에서는 클래스를 끝낼 때마다 쉼표를 찍는 게 보기 좋다.
- 위젯에 위젯에 위젯을 쌓아간다.
- 결론: 온세상이 다 위젯 타입으로 구성되어 있다. 위젯을 블록 쌓듯이 위젯에 위젯을 쌓아가며 앱을 만든다.
복습
- 위젯은 build메소드를 구현해야 한다. 그리고 이 메서드는 또 다른 widget을 리턴해야 한다.
- 자동완성 되는 위젯의 다양한 기능들을 보고 디자인적으로 다양하게 써먹을수 있다. background, elevation 등등..
- 위젯을 리턴해야하는 위젯을 리턴해야 하는 위젯을 리턴해야 하는…
클래스 복습
class Player{
String name = 'nico';//player 기본값
Player(this.name);
//아래에서 처음에 생성할때 괄호 안에 받는 걸로 그 인스턴스의 name 설정할수 있게함
}
void main(){
var nico= Player("potato");
// 앞에 new 생략 됨, 새로운 player 만듬
nico.name //potato
}
class Player{
String name = 'nico';//player 기본값
Player({requried this.name});
//아래에서 처음에 생성할때 괄호 안에 받는 걸로 그 인스턴스의 name 설정할수 있게함
}
void main(){
var nico= Player(name: "potato");
// 앞에 new 생략 됨, 새로운 player 만듬
nico.name //potato
}
- 위젯을 사용할때마다 클래스를 인스턴스화하는 것과 같다. 즉 모든 값 앞에 new를 붙이는 것과 같다. 다만, dart는 그럴 필요가 없어 쓰지 않는다.
- 우리가 앞에서 만든 hello world 위젯들은 클래스를 순서 상관없이 :을 사용하는 named parameter 방식으로 넘기는 것 과 같다.
- 중괄호를 쓰면 괄호 안을 :를 사용하는 named로 받아야 한다.
- 자료형 앞에 ?를 붙이면 인스턴스에 해당 자료형 없어도 됨 선택이 되는 것 이는 위젯들도 마찬가지다. 마우스를 올리면 알 수 있다. 위젯의 필수 자료형이 빠져있다면 오류창이 뜰 것이다.
- default를 이용하고 싶지 않다면, 변수의 자료형 앞에 required를 적어주면 무조건 값을 할당해야 한다는 것을 알기에 nullsafety 하게 쓸 수 있다. (이전 강의 요약 참고함)
UI Challenge
Header, Developer Tools
import 'package:flutter/material.dart';
void main(){
runApp(App());
}
//App 클래스는 여기서 root 역할을 한다.
class App extends StatelessWidget{
@override // 부모클래스에 있는 그러니까 원래 StatelessWidget에 있는 build 메소드를 가져다 쓴다.
Widget build(BuildContext context){//context는 나중에 설명
return MaterialApp(
home: Scaffold(
backgroundColor: Color(0xFF181818),//배경색 약간 검정
body: Padding(
padding: EdgeInsets.symmetric(horizontal:40),//가로방향 간격 40
child:Column(//투명박스와 텍스트 박스로 구분하는 콜롬들
children: [
SizedBox(
height: 80,//맨 위에 80만큼의 공백을 차지하는 투명 박스
),
Row(//하나의 row 안에 즉 하나의 가로줄 안에 두가지의 콜롬 텍스트가 들어간다.
mainAxisAlignment: MainAxisAlignment.end,//가로줄의 맨 끝으로 정렬한다.
children:[//row의 유일한 children
Column(children:[//column은 세로줄 정렬로 children을 가진다. children에 오는 순서대로 세로줄을 하나씩 쌓아간다.
Text('Hey, Selena',
style: TextStyle(
color: Colors.white,
fontSize: 28,
fontWeight: FontWeight.w800,//폰트 굵기 설정
),
),
Text('Welcome back',
style: TextStyle(
color: Colors.white.
withOpacity(0.8),//투명도 살짝 주기
fontSize:18),
),//Text
],//Column(children:
)// Column
],//children
)//Row
],//children
),//child:Column
), //body: Padding
),//home: Scaffold
);//return MaterialApp
}//Widget
}//class App
- a속성은 b값을 가진다 라고 할 때 a:b로 표기되는데 이때 a의 맨 앞은 소문자 b의 맨 앞은 대문자로 표현된다.
- 속성들은 쉼표와 괄호로 잇는다.
- mainAxisAlignment는 현재 같은 방향으로 정렬, crossAxisAlignment는 현재와 수직방형으로 정렬이다. 즉 column 안에서 main은 수직, cross는 수평, row 안에서 main은 수평, cross는 수직이다.
- padding은 차지하는 공간에 더 많은 가장자리 여유를 준다. all 이면 padding을 모든 방향, only면 직접 수동 지정, symmetric은 수평, 수직 방향이다.
- 에러가 난다면 어딘가에 콤마를 빼먹지 않았는지, 괄호를 닫지 않았는지 확인해 보자
- 색깔은 Color, fromRGBO(24,24,24,1)과 같은 함수로 조정할 수도 있다.
- 개발자 도구를 통해 코드를 바꾸지 않고도 편하게 화면을 미리 보기 할 수 있다. 또한 휴대폰 화면을 클릭해 위젯을 활성화할 수 있다. 자세한 사용 방법은 나중에 3.1강을 참고하자.
- 위젯 안에 위젯으로 하위 위젯을 넣을 때 위젯이 복수개 가능하면 children, 단수개만 가능하면 child를 쓴다.
Button Section
import 'package:flutter/material.dart';
void main(){
runApp(App());
}
//App 클래스는 여기서 root 역할을 한다.
class App extends StatelessWidget{
@override // 부모클래스에 있는 그러니까 원래 StatelessWidget에 있는 build 메소드를 가져다 쓴다.
Widget build(BuildContext context){//context는 나중에 설명
return MaterialApp(
home: Scaffold(
backgroundColor: Color(0xFF181818),
body: Padding(
padding: EdgeInsets.symmetric(horizontal:40),
child:Column(
crossAxisAlignment: CrossAxisAlignment.start,//새로 추가되는 것들왼쪽 정렬
children: [
SizedBox(
height: 80,
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children:[
Column(children:[
Text('Hey, Selena',
style: TextStyle(
color: Colors.white,
fontSize: 28,
fontWeight: FontWeight.w800,
),
),
Text('Welcome back',
style: TextStyle(
color: Colors.white.
withOpacity(0.8),
fontSize:18),
),//Text
],//Column(children:
)// Column
],//children
),//Row
SizedBox(
height: 120,
),//totalbalance과 같은 새로운 글자들 넣는데 그 사이의 간격
Text(
'Total Balance',
style: TextStyle(fontSize: 22, color: Colors.white.withOpacity(0.8),
)
),
SizedBox(height: 5,),//totalbalance와 돈 사이의 간격
Text(
'\\$5 184 482',
style: TextStyle(fontSize: 48,
fontWeight: FontWeight.w600,
color: Colors.white,
)
),
SizedBox(height: 30,),//돈과 버튼 사이의 간격
Row(//버튼들 들어갈 row
children:[
Container(//단순한 상자
decoration: BoxDecoration(color:
Colors.amber,//그 상자를 꾸미는 코드
borderRadius: BorderRadius.circular(45),//상자 끝부분 둥글게
),
child: Padding(
padding: EdgeInsets.symmetric
(vertical: 20, horizontal: 50,),//버튼과 글자사이 갭
child:Text('Transfer',
style:TextStyle(
fontsize: 22)),
)
)],
)
],//children
),//child:Column
), //body: Padding
),//home: Scaffold
);//return MaterialApp
}//Widget
}//class App
- container을 사용해 버튼 같은 상자를 만들 수 있고 borderRadius의 circular로 모서리를 둥글게 만들 수 있다.
VSCode setting, Code Actions
- const는 이미 알고 있는 value+ 변하지 않는 값일 때 앞에 붙이면 최적화가 가능하다.
- vscode 파일을 건드리고 다시 시작하면, 이렇게 특정 부분에 const 붙이는 것을 자동화할 수 있으며, 또 다른 설정을 변경하면부 모와 자식이 누군지 알려주는 줄을 설정할 수 있다.
- 전구 모양을 누르면 리팩토링을 제공한다. 이는 위젯중심의 다트 코드에서 새롭게 위젯이나 컨테이너 등으로 감싸야 할 때나 지울때 괄호, 쉼표 실수등을 줄여준다. 단축키를 통해서 전구를 호출할수도 있다. 아마 컨트롤 이랑 온점키일 것이다.
- vs코드 사용 할때 3.5강 앞부분도 참고하기
Reusable Widgets
import 'package:flutter/material.dart';
void main(){
runApp(App());
}
//App 클래스는 여기서 root 역할을 한다.
class Button extends StatelessWidget{//extend 받아 Button이라는 클래스를 만들어 주었다.
final String text;
final Color bgColor;
final Color textColor;
const Button({
super.key,//나중에 설명
required this.text,
required this.bgColor,
required this.textColor, }); //받아야 하는 변수들
@override
Widget build(BuildContext context){
return Container(
decoration: BoxDecoration(
color:bgColor,
borderRadius: BorderRadius.circular(45),
),
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 20,
horizontal: 50,
),
child:Text(
text,
style:TextStyle(
color: textColor,
fontSize: 20,
),
),
),
);//항상 return 뒤에는 ;
}
}
class App extends StatelessWidget{
@override // 부모클래스에 있는 그러니까 원래 StatelessWidget에 있는 build 메소드를 가져다 쓴다.
Widget build(BuildContext context){//context는 나중에 설명
return MaterialApp(
home: Scaffold(
backgroundColor: const Color(0xFF181818),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal:20),
child:Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 80,
),
const Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Column(children: [
Text(
'Hey, Selena',
style: TextStyle(
color: Colors.white,
fontSize: 28,
fontWeight: FontWeight.w800,
),
),
Text(
'Welcome back',
style: TextStyle(
color: Color.fromRGBO(255,255,255,0.8),
fontSize:18),
),//Text
],//Column(children:
)// Column
],//children
),//Row
const SizedBox(
height: 120,
),
Text(
'Total Balance',
style: TextStyle(fontSize: 22, color: Colors.white.withOpacity(0.8),
)
),
const SizedBox(height: 5,),
const Text(
'\\$5 184 482',
style: TextStyle(fontSize: 48,
fontWeight: FontWeight.w600,
color: Colors.white,
)
),
const SizedBox(height: 30,),
Row(
mainAxisAlignment: MainAxisAlignment.
spaceBetween,//둘 사이의 간격을 적당히 떨어뜨림
children: const[
Button(text: 'Transfer',
bgColor: Color(0xFFF1B33B),
textColor: Colors.black),
Button(text: 'Request',
bgColor: Color(0xFF1F2123),
textColor: Colors.white),
],
)
],//children
),//child:Column
), //body: Padding
),//home: Scaffold
);//return MaterialApp
}//Widget
}//class App
- 전구의 extract widget을 이용하면 추출하여 재사용 가능한 위젯을 만들 수 있다.
- 새로운 파일을 만들고 클래스를 만들어서 반복적인 위젯 작업을 피할 수 있다.
- 설계도 역할을 하는 class는 고정된 값이 아니므로 const가 올 수 없다.
Cards
import 'package:flutter/material.dart';
void main(){
runApp(App());
}
//App 클래스는 여기서 root 역할을 한다.
class Button extends StatelessWidget{//extend 받아 Button이라는 클래스를 만들어 주었다.
final String text;
final Color bgColor;
final Color textColor;
const Button({
super.key,//나중에 설명
required this.text,
required this.bgColor,
required this.textColor, }); //받아야 하는 변수들
@override
Widget build(BuildContext context){
return Container(
decoration: BoxDecoration(
color:bgColor,
borderRadius: BorderRadius.circular(45),
),
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 20,
horizontal: 50,
),
child:Text(
text,
style:TextStyle(
color: textColor,
fontSize: 20,
),
),
),
);//항상 return 뒤에는 ;
}
}
class App extends StatelessWidget{
@override // 부모클래스에 있는 그러니까 원래 StatelessWidget에 있는 build 메소드를 가져다 쓴다.
Widget build(BuildContext context){//context는 나중에 설명
return MaterialApp(
home: Scaffold(
backgroundColor: const Color(0xFF181818),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal:20),
child:Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 80,
),
const Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Column(children: [
Text(
'Hey, Selena',
style: TextStyle(
color: Colors.white,
fontSize: 28,
fontWeight: FontWeight.w800,
),
),
Text(
'Welcome back',
style: TextStyle(
color: Color.fromRGBO(255,255,255,0.8),
fontSize:18),
),//Text
],//Column(children:
)// Column
],//children
),//Row
const SizedBox(
height: 120,
),
Text(
'Total Balance',
style: TextStyle(fontSize: 22, color: Colors.white.withOpacity(0.8),
)
),
const SizedBox(height: 5,),
const Text(
'\\$5 184 482',
style: TextStyle(fontSize: 48,
fontWeight: FontWeight.w600,
color: Colors.white,
)
),
const SizedBox(height: 30,),
Row(
mainAxisAlignment: MainAxisAlignment.
spaceBetween,//둘 사이의 간격을 적당히 떨어뜨림
children: const[
Button(text: 'Transfer',
bgColor: Color(0xFFF1B33B),
textColor: Colors.black),
Button(text: 'Request',
bgColor: Color(0xFF1F2123),
textColor: Colors.white),
],
),
const SizedBox(
height: 100,//간격
),
Row(
crossAxisAlignment:
CrossAxisAlignment.end,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,//세로 기준으로 열의 아래쪽에 가로 기준으로는 적당히 벌리며 정렬
children: [
Text(
'Wallets',
style: TextStyle(
color: Colors.white,
fontSize: 36,
fontWeight: FontWeight.w600,
)
),
Text('View All',
style: TextStyle(
color: Colors.white.withOpacity(0.8),
fontSize: 18,
)),
],),
const SizedBox(
height:20,//아래 euro와 간격
),
Container(
decoration: BoxDecoration(
color: Color(0xFF1f2123),
borderRadius:BorderRadius.circular(25),
),
child: Padding(
padding: const EdgeInsets.all(30),//Euro 글씨의 padding
child:Row(
children:[
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children:[
const Text('Euro',
style:TextStyle(color:
Colors.white,
fontSize:32,
fontWeight: FontWeight.w600,
)
),//9분
const SizedBox(
height: 10,
),
Row(
children:[
Text('6428',
style: TextStyle(
color: Colors.white,
fontSize:20,
)
),
const SizedBox(
width:5
),
Text('EUR',
style: TextStyle(
color: Colors.white.withOpacity(0.8),
fontSize:20,
)),
],
)
],
),
],
),
),
),
],//children
),//child:Column
), //body: Padding
),//home: Scaffold
);//return MaterialApp
}//Widget
}//class App
- 아래쪽 ui를 구성했다.
Icons and Transforms
import 'package:flutter/material.dart';
void main(){
runApp(App());
}
//App 클래스는 여기서 root 역할을 한다.
class Button extends StatelessWidget{//extend 받아 Button이라는 클래스를 만들어 주었다.
final String text;
final Color bgColor;
final Color textColor;
const Button({
super.key,//나중에 설명
required this.text,
required this.bgColor,
required this.textColor, }); //받아야 하는 변수들
@override
Widget build(BuildContext context){
return Container(
decoration: BoxDecoration(
color:bgColor,
borderRadius: BorderRadius.circular(45),
),
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 20,
horizontal: 50,
),
child:Text(
text,
style:TextStyle(
color: textColor,
fontSize: 20,
),
),
),
);//항상 return 뒤에는 ;
}
}
class App extends StatelessWidget{
@override // 부모클래스에 있는 그러니까 원래 StatelessWidget에 있는 build 메소드를 가져다 쓴다.
Widget build(BuildContext context){//context는 나중에 설명
return MaterialApp(
home: Scaffold(
backgroundColor: const Color(0xFF181818),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal:20),
child:Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 80,
),
const Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Column(children: [
Text(
'Hey, Selena',
style: TextStyle(
color: Colors.white,
fontSize: 28,
fontWeight: FontWeight.w800,
),
),
Text(
'Welcome back',
style: TextStyle(
color: Color.fromRGBO(255,255,255,0.8),
fontSize:18),
),//Text
],//Column(children:
)// Column
],//children
),//Row
const SizedBox(
height: 120,
),
Text(
'Total Balance',
style: TextStyle(fontSize: 22, color: Colors.white.withOpacity(0.8),
)
),
const SizedBox(height: 5,),
const Text(
'\\$5 184 482',
style: TextStyle(fontSize: 48,
fontWeight: FontWeight.w600,
color: Colors.white,
)
),
const SizedBox(height: 30,),
Row(
mainAxisAlignment: MainAxisAlignment.
spaceBetween,//둘 사이의 간격을 적당히 떨어뜨림
children: const[
Button(text: 'Transfer',
bgColor: Color(0xFFF1B33B),
textColor: Colors.black),
Button(text: 'Request',
bgColor: Color(0xFF1F2123),
textColor: Colors.white),
],
),
const SizedBox(
height: 100,
),
Row(
crossAxisAlignment:
CrossAxisAlignment.end,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'Wallets',
style: TextStyle(
color: Colors.white,
fontSize: 36,
fontWeight: FontWeight.w600,
)
),
Text('View All',
style: TextStyle(
color: Colors.white.withOpacity(0.8),
fontSize: 18,
)),
],),
const SizedBox(
height:20,
),
Container(
clipBehavior:Clip.hardEdge,
decoration: BoxDecoration(
color: Color(0xFF1f2123),
borderRadius:BorderRadius.circular(25),
),
child: Padding(
padding: const EdgeInsets.all(30),
child:Row(
mainAxisAlignment:MainAxisAlignment.spaceBetween,// euro와 아이콘 떨어뜨리기
children:[
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children:[
const Text('Euro',
style:TextStyle(color:
Colors.white,
fontSize:32,
fontWeight: FontWeight.w600,
)
),//9분
const SizedBox(
height: 10,
),
Row(
children:[
Text('6428',
style: TextStyle(
color: Colors.white,
fontSize:20,
)
),
const SizedBox(
width:5
),
Text('EUR',
style: TextStyle(
color: Colors.white.withOpacity(0.8),
fontSize:20,
)),
],
)
],
),
Transform.scale(
scale: 2.2,
child: Transform.translate(
offset: const Offset(-5,12),
child: const Icon(
Icons.euro_rounded,
color: Colors.white,
size:88,
)
)
)
],
),
),
),
],//children
),//child:Column
), //body: Padding
),//home: Scaffold
);//return MaterialApp
}//Widget
}//class App
- 아래쪽 euro 마크를 아이콘을 이용해서 만들어 주었다.
- clipBehavior은 크기를 벗어난 것을 어떻게 처리할지 결정하는 것인데 Clip.hardEdge로 정하면 크기를 벗어난 것을 잘라낸다. 그렇게 euro 아이콘을 잘랐다.
- size를 크게 늘리면 그 주변을 감싸는 다른 요소들도 덩달아 커진다. 이때는 transform.scale을 이용해 주변크기에 상관없이 줄어들거나 늘어나게 할 수 있다.
- Transform.scale은 Transform.translate를 child로 가진다.
- Transform.translate는 offset을 무조건 가져야만 한다. offset은 (x, y) 좌표를 받아 위치를 이동시킨다.
- Icons를 이용해 다양한 아이콘을 사용할 수 있다.
Reusable Cards
import 'package:flutter/material.dart';
void main(){
runApp(App());
}
//App 클래스는 여기서 root 역할을 한다.
class Button extends StatelessWidget{//extend 받아 Button이라는 클래스를 만들어 주었다.
final String text;
final Color bgColor;
final Color textColor;
const Button({
super.key,//나중에 설명
required this.text,
required this.bgColor,
required this.textColor, }); //받아야 하는 변수들
@override
Widget build(BuildContext context){
return Container(
decoration: BoxDecoration(
color:bgColor,
borderRadius: BorderRadius.circular(45),
),
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 20,
horizontal: 50,
),
child:Text(
text,
style:TextStyle(
color: textColor,
fontSize: 20,
),
),
),
);//항상 return 뒤에는 ;
}
}
class CurrencyCard extends StatelessWidget{
final String name, code, amount;
final IconData icon;
final bool isInverted;
final _blackColor = const Color(0xFF1f2123);
const CurrencyCard({
super.key,
required this.name,
required this.code,
required this.amount,
required this.icon,
required this.isInverted,
});
@override
Widget build(BuildContext context){
return Container(
clipBehavior:Clip.hardEdge,
decoration: BoxDecoration(
color: isInverted ? Colors.white: _blackColor,
borderRadius:BorderRadius.circular(25),
),
child: Padding(
padding: const EdgeInsets.all(30),
child:Row(
mainAxisAlignment:MainAxisAlignment.spaceBetween,
children:[
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children:[
Text(name,
style:TextStyle(color: isInverted?
_blackColor
:Colors.white,
fontSize:32,
fontWeight: FontWeight.w600,
)
),//9분
const SizedBox(
height: 10,
),
Row(
children:[
Text(amount,
style: TextStyle(
color: isInverted?
_blackColor
:Colors.white,
fontSize:20,
)
),
SizedBox(
width:5
),
Text(code,
style: TextStyle(
color: isInverted?
_blackColor
:Colors.white.withOpacity(0.8),
fontSize:20,
)),
],
)
],
),
Transform.scale(
scale: 2.2,
child: Transform.translate(
offset: const Offset(-5,12),
child: Icon(
icon,
color:isInverted?
_blackColor
:Colors.white,
size:88,
)
)
)
],
),
),
);
}
}
class App extends StatelessWidget{
@override // 부모클래스에 있는 그러니까 원래 StatelessWidget에 있는 build 메소드를 가져다 쓴다.
Widget build(BuildContext context){//context는 나중에 설명
return MaterialApp(
home: Scaffold(
backgroundColor: const Color(0xFF181818),
body: SingleChildScrollView(
child:Padding(
padding: const EdgeInsets.symmetric(horizontal:20),
child:Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 80,
),
const Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Column(children: [
Text(
'Hey, Selena',
style: TextStyle(
color: Colors.white,
fontSize: 28,
fontWeight: FontWeight.w800,
),
),
Text(
'Welcome back',
style: TextStyle(
color: Color.fromRGBO(255,255,255,0.8),
fontSize:18),
),//Text
],//Column(children:
)// Column
],//children
),//Row
const SizedBox(
height: 70,
),
Text(
'Total Balance',
style: TextStyle(fontSize: 22, color: Colors.white.withOpacity(0.8),
)
),
const SizedBox(height: 5,),
const Text(
'\\$5 184 482',
style: TextStyle(fontSize: 48,
fontWeight: FontWeight.w600,
color: Colors.white,
)
),
const SizedBox(height: 30,),
Row(
mainAxisAlignment: MainAxisAlignment.
spaceBetween,//둘 사이의 간격을 적당히 떨어뜨림
children: const[
Button(text: 'Transfer',
bgColor: Color(0xFFF1B33B),
textColor: Colors.black),
Button(text: 'Request',
bgColor: Color(0xFF1F2123),
textColor: Colors.white),
],
),
const SizedBox(
height: 100,
),
Row(
crossAxisAlignment:
CrossAxisAlignment.end,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'Wallets',
style: TextStyle(
color: Colors.white,
fontSize: 36,
fontWeight: FontWeight.w600,
)
),
Text('View All',
style: TextStyle(
color: Colors.white.withOpacity(0.8),
fontSize: 18,
)),
],),
const SizedBox(
height:20,
),
const CurrencyCard(
name:'Euro',
code: 'EUR',
amount: '6 428',
icon: Icons.euro_rounded,
isInverted: false,
),
Transform.translate(
offset: const Offset(0,-20),
child: const CurrencyCard(
name:'BitCoin',
code: 'BTC',
amount: '9 785',
icon: Icons.currency_bitcoin,
isInverted: true,
),
),
Transform.translate(
offset: const Offset(0,-40),
child: const CurrencyCard(
name:'Dollar',
code: 'USD',
amount: '428',
icon: Icons.attach_money_outlined,
isInverted: false,
),
),
],//children
),//child:Column
), //body: Padding
),
),//home: Scaffold
);//return MaterialApp
}//Widget
}//class App
- icon 같은 속성도 속성 타입을 class 안에서 정해주고 객체에 맞게 Icons. 아이콘이름을 설정해 줌으로써 객체를 생성할 수 있다.
- wallets 밑의 카드들을 객체화하였다.
- transform.translate의 offset은 원래 그리드로 정해진 위치에서 다른 오브젝트들을 무시하고 이동시킬 수 있다.
- padding 이전 body에 SingleChildScrollView 위젯을 넣음으로써 오버플로우 된 내용은 스크롤 처리할 수 있다.
- isinverted라는 bool을 받아 색상 반전 역시 프로퍼티화 하였다.
- 변수 앞에 _를 붙여 private로 바꿔줄 수 있다.
Code Challenge
import 'package:flutter/material.dart';
void main(){
runApp(App());
}
//App 클래스는 여기서 root 역할을 한다.
class Button extends StatelessWidget{//extend 받아 Button이라는 클래스를 만들어 주었다.
final String text;
final Color bgColor;
final Color textColor;
const Button({
super.key,//나중에 설명
required this.text,
required this.bgColor,
required this.textColor, }); //받아야 하는 변수들
@override
Widget build(BuildContext context){
return Container(
decoration: BoxDecoration(
color:bgColor,
borderRadius: BorderRadius.circular(45),
),
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 20,
horizontal: 50,
),
child:Text(
text,
style:TextStyle(
color: textColor,
fontSize: 20,
),
),
),
);//항상 return 뒤에는 ;
}
}
class CurrencyCard extends StatelessWidget{
final String name, code, amount;
final IconData icon;
final bool isInverted;
final _blackColor = const Color(0xFF1f2123);
final int order;
const CurrencyCard({
super.key,
required this.name,
required this.code,
required this.amount,
required this.icon,
required this.isInverted,
required this.order,
});
@override
Widget build(BuildContext context){
return
Transform.translate(
offset: Offset(0,-20*(order-1)),
child:Container(
clipBehavior:Clip.hardEdge,
decoration: BoxDecoration(
color: isInverted ? Colors.white: _blackColor,
borderRadius:BorderRadius.circular(25),
),
child: Padding(
padding: const EdgeInsets.all(30),
child:Row(
mainAxisAlignment:MainAxisAlignment.spaceBetween,
children:[
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children:[
Text(name,
style:TextStyle(color: isInverted?
_blackColor
:Colors.white,
fontSize:32,
fontWeight: FontWeight.w600,
)
),//9분
const SizedBox(
height: 10,
),
Row(
children:[
Text(amount,
style: TextStyle(
color: isInverted?
_blackColor
:Colors.white,
fontSize:20,
)
),
const SizedBox(
width:5
),
Text(code,
style: TextStyle(
color: isInverted?
_blackColor
:Colors.white.withOpacity(0.8),
fontSize:20,
)),
],
)
],
),
Transform.scale(
scale: 2.2,
child: Transform.translate(
offset: const Offset(-5,12),
child: Icon(
icon,
color:isInverted?
_blackColor
:Colors.white,
size:88,
)
)
)
],
),
),
),
);
}
}
class App extends StatelessWidget{
@override // 부모클래스에 있는 그러니까 원래 StatelessWidget에 있는 build 메소드를 가져다 쓴다.
Widget build(BuildContext context){//context는 나중에 설명
return MaterialApp(
home: Scaffold(
backgroundColor: const Color(0xFF181818),
body: SingleChildScrollView(
child:Padding(
padding: const EdgeInsets.symmetric(horizontal:20),
child:Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 80,
),
const Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Column(children: [
Text(
'Hey, Selena',
style: TextStyle(
color: Colors.white,
fontSize: 28,
fontWeight: FontWeight.w800,
),
),
Text(
'Welcome back',
style: TextStyle(
color: Color.fromRGBO(255,255,255,0.8),
fontSize:18),
),//Text
],//Column(children:
)// Column
],//children
),//Row
const SizedBox(
height: 70,
),
Text(
'Total Balance',
style: TextStyle(fontSize: 22, color: Colors.white.withOpacity(0.8),
)
),
const SizedBox(height: 5,),
const Text(
'\\$5 184 482',
style: TextStyle(fontSize: 48,
fontWeight: FontWeight.w600,
color: Colors.white,
)
),
const SizedBox(height: 30,),
const Row(
mainAxisAlignment: MainAxisAlignment.
spaceBetween,//둘 사이의 간격을 적당히 떨어뜨림
children: [
Button(text: 'Transfer',
bgColor: Color(0xFFF1B33B),
textColor: Colors.black),
Button(text: 'Request',
bgColor: Color(0xFF1F2123),
textColor: Colors.white),
],
),
const SizedBox(
height: 100,
),
Row(
crossAxisAlignment:
CrossAxisAlignment.end,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
const Text(
'Wallets',
style: TextStyle(
color: Colors.white,
fontSize: 36,
fontWeight: FontWeight.w600,
)
),
Text('View All',
style: TextStyle(
color: Colors.white.withOpacity(0.8),
fontSize: 18,
)),
],),
const SizedBox(
height:20,
),
const CurrencyCard(
name:'Euro',
code: 'EUR',
amount: '6 428',
icon: Icons.euro_rounded,
isInverted: false,
order:1,
),
const CurrencyCard(
name:'BitCoin',
code: 'BTC',
amount: '9 785',
icon: Icons.currency_bitcoin,
isInverted: true,
order:2,
),
const CurrencyCard(
name:'Dollar',
code: 'USD',
amount: '428',
icon: Icons.attach_money_outlined,
isInverted: false,
order:3,
),
],//children
),//child:Column
), //body: Padding
),
),//home: Scaffold
);//return MaterialApp
}//Widget
}//class App
- 기존의 코드에서 transform.translate이 거추장스러우니 코드를 줄이고 클래스화 시키는 발전과제다.
- 기존의 코드에서 transform.translate까지 위젯에 포함시키고, offset은 order 1,2,3으로 받아 계산하였다
반응형
'개발 > 클론코딩' 카테고리의 다른 글
[Nomad Coders ]Flutter로 웹툰 앱 만들기 (1) | 2024.01.11 |
---|---|
[Nomad Coders] Flutter로 Pomodoros 앱 만들기 (1) | 2024.01.10 |
[Nomad Coders] Flutter 를 위한 DART 문법 요약 (1) | 2024.01.09 |
JavaScript로 테트리스 만들기, 코린이가 코린이를 위한 A-Z 설명 4 (完) (0) | 2023.05.08 |
JavaScript로 테트리스 만들기, 코린이가 코린이를 위한 A-Z 설명 3 (0) | 2023.04.29 |