들어가기 앞서...
저번 게시글들을 통해서 배운 것들을 복습하며 만들수 있는, 처음 만난 날짜를 입력해서 현재 몇일이 지났는지를 숫자로 표시 해주는 간단한 프로젝트를 만들 것이다.
주의 깊게 봐야하는 점...
- Font 적용
- DatePicker
- 날짜 다루기
- 테마 적용하기
본문으로...
이제부터 만들 화면의 결과물을 미리 게시글에 올려본다!
두가지 부분을 나눠서 보겠다!
텍스트들은 윗부분, 사진은 아랫부분
- 우선 main.dart 와 HomeScreen.dart 페이지를 준비준다!
- 폰트와 이미지를 준비해주자!
이미지는 각자 알아서!
폰트 : https://fonts.google.com/
Google Fonts
Making the web more beautiful, fast, and open through great typography
fonts.google.com
준비해둔 이미지와 폰트를 프로젝트내에 추가 해줄 것인데, 이미지는 자주했었고, 폰트설정은 처음이다!
- pubspec.yaml 파일을 열어라!
...
flutter:
...
assets:
- asset/img/
fonts:
- family: parisienne
fonts :
- asset: asset/font/Parisienne-Regular.ttf
- family: sunflower
fonts:
- asset: asset/font/Sunflower-Light.ttf
- asset: asset/font/Sunflower-Medium.ttf
weight: 500
- asset: asset/font/Sunflower-Bold.ttf
weight: 700
...
이렇게 적어주면 된다!.
assets 에는 이미지 경로를 적어주고, fonts 에는 family 에는 폰트의 이름을 적어준다.
family 안에 fonts 는 이미지 와 마찬가지로 asset 을 적고, weight 가 추가된 것이 있는데, font 마다 글씨체의 굵기를 추가해주고 싶어서 추가해준 것이다.(취향 별~ 안써도 무관하다.)
마지막으로 pub get! 해주기!
- TextStyle() 으로 기본 스타일링 적용 및 font 적용하기.
꿀팁💡 초반에 접근 쉽게 하는 방법 💡
러프하게 접근해라!
class _HomeScreenState extends State<HomeScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.pink[100],
body: SafeArea(
bottom: false,
child: Container(
width: MediaQuery.of(context).size.width,
child: Column(
children: [
Text('U&I'),
Text('우리 처음 만난 날'),
Text('2020.01.01'),
IcomButton(onPressed:(){}, icon:Icon(Icons.favorite)),
Text('D+1'),
]
)
),
));
}
}
간단하게 한번 보면서 살펴보겠다!
위젯들은 세로로 되어있으니, Column 으로 Text() 3개 와 Icon() 1개, Text() 1개 로 _TopPart 클래스를 선언해주면 된다.
SafeArea() 위젯을 제일 위에 감싸 상단에 글씨가 사라지는것을 막고, bottom 은 사진이 내려와야하니, false 로 해주자!
각 텍스트 마다 TextStyle(fontFamily : 를 pubspec.yaml 에 저장해놓은 데로 적어주면 된다.) 적용해주고, fontSize 도 각각 적용해주자!
IconButton(... icon)은 플러터에서 제공하는 Icons.favorite 을 해주면 하트 모양이 나온다!
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.pink[100],
body: SafeArea(
bottom: false,
child: Container(
width: MediaQuery.of(context).size.width,
child:
_TopPart(),
),
));
}
}
backgroundColor 를 보면, Colors.pink 까지는 봤는데, [100] 되어있다
기본 플러터에서 제공해주는 색깔은 500 의 투명도를 가지고 있다.
하지만 그것보다 얀하게 100, 그것보다 진하게 900 까지 조절 할 수 있다.
그리고 코드가 길어지기 시작하니, 따로 뺴주기로 하자! 커맨드(stless)로 _TopPart(); 로 뺐다!
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.pink[100],
body: SafeArea(
bottom: false,
child: Container(
width: MediaQuery.of(context).size.width,
child: _TopPart(),
),
));
}
}
class _TopPart extends StatelessWidget {
const _TopPart({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(
'U&I',
style: TextStyle(
color: Colors.white,
fontFamily: 'parisienne',
fontSize: 80.0,
),
),
Text(
'우리 처음 만난 날',
style: TextStyle(
color: Colors.white,
fontFamily: 'sunflower',
fontSize: 30.0),
),
Text(
'2020.01,01',
style: TextStyle(
color: Colors.white, fontFamily: 'sunflower', fontSize: 20.0),
),
IconButton(
iconSize: 60.0,
onPressed: () {
},
icon: Icon(
Icons.favorite,
color: Colors.red,
)),
Text(
'D+1',
style: TextStyle(
color: Colors.white,
fontFamily: 'sunflower',
fontWeight: FontWeight.w700,
fontSize: 50.0),
)
],
);
}
}
그리고 하단에 이미지를 추가해죽겠다!
...
class _HomeScreenState extends State<HomeScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.pink[100],
body: SafeArea(
bottom: false,
child: Container(
width: MediaQuery.of(context).size.width,
child: Column(
children: [
_TopPart(),
_BottomPart(),
],
),
),
));
}
}
...
class _BottomPart extends StatelessWidget {
const _BottomPart({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Image.asset('asset/img/middle_image.png');
}
}
- Expended 위젯을 감싸주겠다!
하단에 이미지를 넣고 앱을 실행해보겠다!
터미널에도 이렇게 이슈사항들이 뜬다.
======== Exception caught by rendering library =====================================================
The following assertion was thrown during layout:
A RenderFlex overflowed by 178 pixels on the bottom.
The relevant error-causing widget was:
Column Column:file:///Users/hitang/Documents/flutter_project/hello_world_first/lib/screen/home_screen.dart:364:20
The overflowing RenderFlex has an orientation of Axis.vertical.
The edge of the RenderFlex that is overflowing has been marked in the rendering with a yellow and black striped pattern. This is usually caused by the contents being too big for the RenderFlex.
Consider applying a flex factor (e.g. using an Expanded widget) to force the children of the RenderFlex to fit within the available space instead of being sized to their natural size.
This is considered an error condition because it indicates that there is content that cannot be seen. If the content is legitimately bigger than the available space, consider clipping it with a ClipRect widget before putting it in the flex, or using a scrollable container rather than a Flex, like a ListView.
The specific RenderFlex in question is: RenderFlex#f78d5 relayoutBoundary=up3 OVERFLOWING
... parentData: <none> (can use size)
... constraints: BoxConstraints(w=430.0, 0.0<=h<=873.0)
... size: Size(430.0, 873.0)
... direction: vertical
... mainAxisAlignment: start
... mainAxisSize: max
... crossAxisAlignment: center
... verticalDirection: down
◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤
====================================================================================================
이 이슈 사항이 뜨는 이유는 Row 나 Column 등의 자식들이 이미 화면 사이즈는 넘어섰을때나 공간이 없을 때 개발단계에서만 출력이 됩니다. 배포했을때는 문제없이 진행 된다고 한다.
그래서 플러터에서는 자식이 사용가능한 공간을 채우도록, Row 나 Column 또는 Flex 의 자식을 확장하는 위젯이다.
Expanded 위젯을 사용하면 Row, Column 또는 Flex 의 자식이 확장되어 기본축을 따라 사용 가능한 공간을 채운다.
여러 자식이 확장된 경우 사용 가능한 공간은 flex factor 에 따라 분할된다.
자세한 것은 Documents 를 확인해보자!
https://api.flutter.dev/flutter/widgets/Expanded-class.html
Expanded class - widgets library - Dart API
A widget that expands a child of a Row, Column, or Flex so that the child fills the available space. Using an Expanded widget makes a child of a Row, Column, or Flex expand to fill the available space along the main axis (e.g., horizontally for a Row or ve
api.flutter.dev
그러므로 이미지에 Expanded 위젯을 씌워주고, Column 에도 Expanded 위젯을 씌워주자!
이미지는 저작권으로 흰색으로 가려놨으니, 흰색으로 크기를 가늠하자!
마지막으로 Column 주축으로 공간을 MainAxisAlignment.spaceBetween 를 적용해보겠다!
하지만 우리가 원하는것은 우리 처음 만난 날 과 202.01.01이 붙었으면 좋겠다! 하지만 위젯들의 공간들을 일정하게 골백을 주는 것이 spaceBetween 이다. 그렇다면, 다른 방법은 Column 위젯으로 묶어 주면 된다!
최종코드)
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.pink[100],
body: SafeArea(
bottom: false,
child: Container(
width: MediaQuery.of(context).size.width,
child: Column(
children: [
_TopPart(),
_BottomPart(),
],
),
),
));
}
}
class _TopPart extends StatelessWidget {
const _TopPart({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'U&I',
style: TextStyle(
color: Colors.white,
fontFamily: 'parisienne',
fontSize: 80.0,
),
),
Column(
children: [
Text(
'우리 처음 만난 날',
style: TextStyle(
color: Colors.white,
fontFamily: 'sunflower',
fontSize: 30.0),
),
Text(
'2020.01.01',
style: TextStyle(
color: Colors.white,
fontFamily: 'sunflower',
fontSize: 20.0),
),
],
),
IconButton(
iconSize: 60.0,
onPressed: () {
// showCupertinoDialog(context: context, builder: builder)
},
icon: Icon(
Icons.favorite,
color: Colors.red,
)),
Text(
'D+1',
style: TextStyle(
color: Colors.white,
fontFamily: 'sunflower',
fontWeight: FontWeight.w700,
fontSize: 50.0),
)
],
),
);
}
}
class _BottomPart extends StatelessWidget {
const _BottomPart({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Expanded(child: Image.asset('asset/img/middle_image.png'));
}
}
끝으로...
- 프로젝트를 러프하게 접근하는 방법을 알 수 있었다!
- 위젯마다 폰트를 적용할 수 있었다!
- Expanded 의 사용법과 사용 이유를 알 수 있었다!
- 코드를 밖으로 빼서 가독성이 좋게 분리하는 방법을 알았다!
