버튼 등의 기능은 없지만 디자인을 그대로 만들어볼 것이다.
다음 부분을 만들어볼 것이다.
위를 구현한 코드는 다음과 같다.
class App extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Color(0xFF181818),
body: Padding(
padding: EdgeInsets.symmetric(
horizontal: 40,
),
child: Column(
children: [
SizedBox(
height: 80,
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'Hey, Selena',
style: TextStyle(
color: Colors.white,
fontSize: 28,
fontWeight: FontWeight.w800,
),
),
Text(
'Welcome back',
style: TextStyle(
fontSize: 18,
color: Colors.white.withOpacity(0.8),
),
),
],
),
],
),
],
),
),
),
);
}
}
Column과 Row
웹 프론트엔드와 마찬가지로 박스로 생각하면 쉽다. 전체적인 화면구성은 세로로 쌓여있는 구조로, Column 구조이다. 그리고 그 안의 헤더 부분을 보면 가로로 이어져 있는 Row 구조를 띄고 있다. 이 구조를 잘 이해해야 한다. 이들은 각각 하나의 child를 가지고 이들은 list 자료형이다. 마우스를 갖다 대면 알 수 있다. Column에서 가운데 정렬 혹은 왼쪽 정렬, 오른쪽 정렬을 하기 위해서는 CrossAxisAlignment를 사용한다. Row에서는 반대이다. flexbox와 유사하다. 정리하면 Row의 가로가 main, Column의 세로가 main이다.
SizedBox
Column에서 하나의 속성이 위에 딱 붙을 때 조금은 떨어뜨려놓을 수 있도록 빈 박스를 만드는 것이다. height 등을 지정할 수 있다.
Text 및 Text 관련 속성들
CSS와 상당히 유사한데 조심할 점은 지정할 때 자료형을 잘 봐야한다. 하나 알아둬야 하는 것은 withOpacity이다. 이는 투명도를 조절할 수 있다.
Padding
Padding은 html과 css 처럼 사용할 수 있는데 어떤 방식으로 패딩을 하는지에 따라 사용할 속성이 달라진다. 여기서는 Edgeinsets를 사용했다.
5.Color
색을 지정하기 위해서 Colors를 이용할 수 있지만 컬러코드를 따온다면 다음과 같이 0xFF를 쓰고 6자리 코드를 적음으로써 지정할 수 있다.
backgroundColor: Color(0xFF181818),
devtool은 vscode 상에서 다음의 버튼을 클릭함으로써 활성화할 수 있다.
이 툴을 사용하면 우리가 크롬에서 사용했던 개발자 도구와 유사한 기능들, 혹은 더 나은 기능들을 사용할 수 있다.
이번 강의에서는 다음 부분을 만들었다.
Total Balance와 금액 텍스트는 다음의 코드를 입력하여 완성하였다. 이에 대한 내용은 위와 동일하니 패스한다.
SizedBox(
height: 120,
),
Text(
'Total Balance',
style: TextStyle(
fontSize: 22,
color: Colors.white.withOpacity(0.8),
),
),
SizedBox(
height: 5,
),
Text(
'\$5 194 482',
style: TextStyle(
fontSize: 44,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
한가지 알아두어야할 것은 $를 그대로 쓰면 그 뒤에 오는 5를 변수 취급하기 때문에 역슬래시를 이용하여 string임을 명시해줘야한다.
다음은 버튼을 만드는 것인데 이는 Container라는 위젯을 사용한다. html의 div와 유사하다. 우선은 노란 버튼 하나만 만들었다. 코드는 아래와 갇다.
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: 20,
),
),
)),
],
),
우선 버튼 2개가 가로로 배치되어있으므로 Row 위젯을 사용한다. 그리고 첫번째 container를 작성한다. container를 꾸밀 때는 decoration을 이용한다. BoxDecoration을 이용하여 그 안에서 색깔 혹은 보더를 지정할 수 있다.
버튼 안의 텍스트를 패딩 없이 하면 글자크기에 딱 맞는 정도의 박스가 생성되는데 우리가 만들 버튼은 어느 정도 패딩이 존재하기 때문에 패딩을 지정해줬다.
vscode로 dart를 사용하다보면 파란 물결 줄이 계속 뜬다. 이는 경고 메세지 때문이다. const를 권고하는 내용이다. 그래서 실제로 Color같은 속성 앞에 const를 쓰면 줄이 사라진다. 이것을 하나하나 하면서 물결 줄을 없애기에는 너무 귀찮고 정확하지 않을 수 있다. 그래서 vscode의 설정을 통해 이를 해결한다. 명령 팔레트에 open users setting을 치면 json 파일이 열린다. 거기에 다음을 추가한다.
"editor.codeActionsOnSave": {"source.fixAll": true},
이러면 줄이 다 사라진다.
또 하나의 유용한 기능은 부모-자식 간의 관계를 시각적으로 나타내주는 기능이다. 다음 코드를 위의 설정 json 파일에 넣어준다.
"dart.previewFlutterUiGuides": true,
이렇게 되면 아래와 같이 종속관계가 시각적으로 나타난다.
헤더를 만들 때 패딩을 줘야 했었다. 그래서 방대한 양을 잘라내기 해서 padding의 괄호 안에 붙여넣기를 했다. 더 방대한 양도 동일하게 하기에는 어려움이 있고 이 자체가 귀찮은 일이다. 그래서 우리는 code action을 사용한다. 이는 간혹가다 보이는 노란 전구이다. 이걸 누르면 우리가 적용하고 싶은 위젯으로 둘러싸게 해준다. 혹은 단축키 '커맨드 + .'를 둘러싸고자 하는 최상위 위젯에 커서를 두고 누르면 동일한 기능을 사용할 수 있다.
시작하기에 앞서 vscode에 error lens 확장팩을 다운로드한다. 위에서 만든 버튼 옆에 버튼 하나를 더 만드려고 한다. 단순하게 복사붙여넣기 하고 배경, 텍스트 등을 바꾸기만 하면 완성이다. 다만 이렇게 하다보면 다음과 같은 경고창이 나타난다.
이것은 픽셀이 패딩에 오버플로우 됐음을 알려준다. 따라서 적절하게 전체 패딩을 줄여준다.
그리고 위에 보면 현재 버튼 끼리 딱 붙어있으므로 다음의 속성을 Row에 추가하여 떨어뜨려준다.
mainAxisAlignment: MainAxisAlignment.end,
그러나 이렇게 복사 붙여넣기 하는 것은 너무나 비효율적이다. 그러므로 우리는 재사용할 수 있게 만들어야한다. 단순하게 Container 앞에서 전구를 눌러 'extract widget'을 할 수 있지만, 공부를 위해 기초적인 방법으로 진행했다.
먼저 main.dart 파일과 동일한 폴더 내에 widgets 폴더를 형성하고 그 안에 Button.dart 파일을 형성한다. 그 안에 새로운 위젯을 설정하고 return 부분에 처음에 디자인했던 Container를 복사붙여넣기 한다. 그럼 다음과 같은 코드를 작성하게 된다.
import 'package:flutter/material.dart';
class Button extends StatelessWidget {
final String text;
final Color bgColor;
final Color textColor;
const Button(
{super.key,
required this.text,
required this.bgColor,
required this.textColor});
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(
fontSize: 20,
color: textColor,
),
),
),
);
}
}
우리는 Button 위젯을 재사용하면서 텍스트, 배경색깔, 텍스트 색깔을 바꿔야한다. 그러므로 프로퍼티들을 지정해주고 그 다음 생성자를 만들어준다. 이때 Button은 const가 아니므로 const 지워준다. 이렇게 만든 Button 위젯을 다음과 같이 사용할 수 있다.
const Button(
text: 'Transfer',
bgColor: Color(0xFFF1B33B),
textColor: Colors.black,
),
const Button(
text: 'Request',
bgColor: Color(0xFF1F2123),
textColor: Colors.white,
),
다트에는 다트 자체적으로 제공하는 아이콘이 있다. 그것을 사용하기 위해선 Icon()을 쓰면 된다. 예시는 아래와 같다.
Icon(
Icons.euro_rounded,
size: 88,
color: Colors.white,
),
container 안에 내용물의 사이즈를 변화시키면 그 사이즈에 따라 container의 크기도 같이 변한다. 만약 내용물의 사이즈만 변화시키고 싶을 때 transformation.scale을 사용한다. 그 예시는 아래와 같다.
Transform.scale(
scale: 2.2,
...),
어떤 객체의 위치를 절대적으로 움직이기 위해 사용할 수 있다. 지금까지는 spaceBetween 으로 간격 띄우기만을 했다면 이제는 직접적으로 OffSet을 주어서 위치를 지정할 수 있다.
Transform.translate(
offset: const Offset(-5, 12),
...)
크기가 컨테이너를 넘는 아이콘이 있을 때 넘은 것을 가릴 수 있게 하는 것이다. 다른 옵션도 있으니 확인하면 된다. 다음과 같이 사용한다.
...
clipBehavior: Clip.hardEdge,
...
Clip.None이면 컨테이너를 넘어도 자르지 않고, Clip.hardEdge이면 컨테이너를 넘은 부분을 잘라낸다.
카드를 재사용하기 위해서 버튼을 재사용하기 위해 위젯 파일을 따로 만든 것과 동일한 작업을 한다.
그러나 결과물을 보면 모든게 다 동일한데 비트코인 카드만 배경색과 글자색이 반전된 것을 확인할 수 있다. 이를 위해 추가적인 프로퍼티를 넣어야한다. IsInverted라는 변수를 지정하여 구현하였고 코드는 아래와 같다.
class CurrencyCards extends StatelessWidget {
...
final bool IsInverted;
...
const CurrencyCards({
super.key,
required this.name,
required this.code,
required this.amount,
required this.icon,
required this.IsInverted,
});
Widget build(BuildContext context) {
return Container(
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
color: IsInverted ? Colors.white : _blackColor,
borderRadius: BorderRadius.circular(20),
),
...
};
IsInverted도 입력값이 필요하므로 생성자를 만들어줘야한다. 그렇기 때문에 required this.IsInverted 를 넣어야한다. 이렇게 만든 변수는
color: IsInverted ? Colors.white : _blackColor
처럼 물음표 조건문을 통해 조건에 따라 속성이 변하도록 설정할 수 있다.
이것은 사용자가 화면을 스크롤 할 수 있도록 해주는 위젯이다.
home: Scaffold(
backgroundColor: const Color(0xFF181818),
body: SingleChildScrollView(
...
이처럼 Scaffold의 body에 위젯으로 씌워 구현한다.