Flutter Basic Chapter 2 - 다크 테마 월렛 대시보드
헤더와 다크 배경 구성
🎯 이번 단계에서 배울 것
- 화면 전체 배경색과 여백을 잡아 기본 레이아웃 만들기
Row
,Column
을 조합해 우측 상단 인사 헤더 정렬하기- 불투명도(
Opacity
)를 이용해 텍스트 명암 대비 조절하기 - 다크 테마 UI에서 자주 사용하는 색상 코드를 적용하기
📂 파일 구조
1 | 수정되는 파일 |
📝 1단계: 헤더 UI 배치하기
전체 코드 (lib/main.dart @ 2.0):
1 | import 'package:flutter/material.dart'; |
🔍 코드 상세 설명
1. 다크 테마 배경 지정
1 | backgroundColor: Color(0xFF181818) |
- 16진 색상 코드로 거의 검정에 가까운 회색을 지정했습니다.
- 다크 테마에서는 고대비 흰색 텍스트와 조합해 가독성을 확보합니다.
2. 전체 여백과 상단 패딩 확보
1 | Padding( |
- 좌우 40px 여백으로 콘텐츠가 화면 모서리에 붙지 않게 합니다.
SizedBox
로 상단 공간을 만들어 노치 영역이나 상태바와 겹치지 않도록 합니다.
3. 헤더 정렬 전략
1 | Row( |
Row
를 사용해 헤더 전체를 오른쪽 끝에 배치했습니다.- 내부
Column
도crossAxisAlignment.end
로 맞춰 두 줄의 텍스트가 오른쪽 정렬되도록 했습니다.
4. 텍스트 스타일 대비
1 | color: Color.fromRGBO(255, 255, 255, 0.8) |
- 두 번째 문자열은 살짝 투명도를 주어 강조 계층을 만들었습니다.
fromRGBO
의 마지막 파라미터(0.8)가 알파값(불투명도)입니다.
시각화:
1 | ┌──────────────────────────────────┐ |
🎨 화면 미리보기
1 | 다크 배경 + 우측 상단 인사말 두 줄 |
📊 동작 흐름
1 | 1. Scaffold가 0xFF181818 배경을 그림 |
✅ 체크리스트
- 배경색과 텍스트 색 대비가 충분한가?
- 헤더가 화면 오른쪽 상단에 맞춰졌는가?
- 두 번째 텍스트가 살짝 흐리게 표현되는가?
💡 연습 과제
- 헤더 이름을 본인 이름으로 바꿔보세요.
SizedBox(height: 80)
값을 줄여 상단 여백 변화를 확인하세요.Color.fromRGBO
의 알파값을 0.5로 변경해 투명도 차이를 느껴보세요.
잔액 정보와 CTA 버튼 추가 (feat. Const 최적화)
🎯 이번 단계에서 배울 것
Column
에 텍스트를 차곡차곡 쌓아 계층적 정보를 표현하기withOpacity
로 텍스트 색상 밝기를 빠르게 조절하기Container
와BoxDecoration
으로 버튼 형태 만들기const
키워드로 위젯을 고정해 성능과 핫리로드 효율 개선하기
📂 파일 구조
1 | 수정되는 파일 |
📝 1단계: 잔액 섹션과 버튼 만들기
추가된 코드 핵심 (lib/main.dart @ 2.2~2.3):
1 | const SizedBox(height: 120), |
🔍 코드 상세 설명
1. withOpacity
로 명암 조절
1 | color: Colors.white.withOpacity(0.8) |
- 이미 존재하는 컬러에 간단히 투명도를 입혀 강조 수준을 조절합니다.
- RGBO보다 간결하여 빠르게 반복 적용할 수 있습니다.
2. 큰 숫자 폰트와 두께
1 | fontSize: 48, |
- 잔액 정보는 한눈에 들어와야 하므로 큰 글씨와 굵은 두께를 사용합니다.
- Flutter의
FontWeight
는 100~900 사이 굵기를 선택할 수 있습니다.
3. 버튼 레이아웃
1 | Container → BoxDecoration → borderRadius: BorderRadius.circular(45) |
- 컨테이너 배경색을 노란색으로 칠하고 모서리를 둥글게 잘랐습니다.
Padding
으로 내부 여백을 주어 버튼이 답답해 보이지 않게 합니다.
4. const
키워드 활용 (2.3 커밋)
- 값이 변하지 않는 위젯 앞에
const
를 붙여 위젯 트리를 불변으로 표시합니다. - Flutter는 const 위젯을 재사용하므로 리빌드 때 성능이 좋아집니다.
const Color(...)
처럼 생성자에도const
를 붙여야 완전히 불변으로 취급됩니다.
비교 예시:
1 | // Before (non-const) |
시각화:
1 | ┌─────────────────────────────┐ |
🎨 화면 미리보기
1 | 잔액 텍스트 아래 노란색 Transfer 버튼이 나타난 모습 |
📊 동작 흐름
1 | 1. Column이 잔액 텍스트와 버튼을 위→아래로 배치 |
✅ 체크리스트
-
Total Balance
텍스트가 살짝 회색빛으로 표현되는가? - 잔액 숫자가 굵고 크게 표시되는가?
- 버튼이 둥근 사각형 형태로 렌더링되는가?
- 변하지 않는 위젯에
const
가 붙어 있는가?
💡 연습 과제
Request
버튼을 추가로 만들어Row
안에 나란히 배치해보세요.- 버튼 색상을 다른 브랜드 컬러로 바꿔 보고 어울리는지 확인하세요.
const
를 붙일 수 있는 다른 위젯이 없는지 찾아보고 적용하세요.
재사용 가능한 버튼 위젯 추출
🎯 이번 단계에서 배울 것
- 위젯을 별도 파일로 분리해 재사용성을 높이기
- 생성자 파라미터에
required
와final
을 사용해 안전한 위젯 설계하기 main.dart
에서 커스텀 위젯 두 개를 서로 다른 테마로 배치하기
📂 파일 구조
1 | 새로 생성되는 파일 |
📝 1단계: Button 위젯 정의하기
전체 코드 (lib/widgets/button.dart @ 2.5):
1 | import 'package:flutter/material.dart'; |
🔍 코드 상세 설명
1. StatelessWidget
으로 재사용성 확보
- 버튼 내용(text)과 스타일(bgColor, textColor)을 파라미터로 받아 다양한 조합을 지원합니다.
- 상태 변화가 없으므로
StatelessWidget
이 적합하며, 불필요한 상태 관리를 피할 수 있습니다.
2. required
와 final
- 생성자에
required
를 추가해 필수 인수를 누락하면 컴파일 시점에 바로 오류가 납니다. - 멤버 변수를
final
로 선언해 위젯이 불변이라는 것을 명시합니다.
3. 기존 Container 코드 재사용
- 2.2에서 작성한 버튼 스타일을 그대로 옮겨 왔기 때문에 UI가 변하지 않습니다.
padding
도 함께 포함하여 호출하는 쪽에서 반복할 필요가 없습니다.
📝 2단계: main.dart에서 Button 사용하기
1 | Row( |
Row
의mainAxisAlignment.spaceBetween
으로 두 버튼을 좌우 끝에 배치했습니다.- 같은 위젯이라도 색 조합만 바꿔 완전히 다른 느낌을 줄 수 있음을 보여줍니다.
비교 예시:
1 | // Before |
🎨 화면 미리보기
1 | [ Transfer ] [ Request ] ← 동일한 버튼 위젯의 두 가지 스타일 |
📊 동작 흐름
1 | 1. main.dart가 Button 클래스를 임포트 |
✅ 체크리스트
-
lib/widgets/button.dart
파일이 생성되었는가? - Button 위젯의 모든 인수가
required
로 선언되었는가? - main.dart에서 두 버튼 색상이 정확히 다르게 표시되는가?
💡 연습 과제
Button
위젯에icon
파라미터를 추가하고 아이콘이 있는 버튼을 만들어보세요.- 버튼 너비를
double
파라미터로 받아 다양한 길이를 지원하게 확장해보세요. GestureDetector
를 감싸 클릭 이벤트를 받을 준비를 해보세요.
월렛 카드 UI 구성
🎯 이번 단계에서 배울 것
- 둥근 카드 컨테이너 안에 텍스트를 세로로 배치하기
crossAxisAlignment.end
와spaceBetween
으로 제목/바로가기 배치하기- 통화 금액과 단위를 나란히 배치하는
Row
구성 이해하기
📂 파일 구조
1 | 수정되는 파일 |
📝 1단계: Wallets 타이틀과 카드 만들기
1 | const SizedBox(height: 100), |
🔍 코드 상세 설명
1. 섹션 헤더 배치
crossAxisAlignment.end
로Wallets
제목과View All
을 baseline에 맞춰 자연스러운 시선을 유도합니다.View All
은withOpacity
로 살짝 흐려 보조 정보임을 표현합니다.
2. 카드 컨테이너
- 배경색을 한 단계 밝게(0xFF1F2123) 설정해 메인 배경과 구분했습니다.
borderRadius.circular(25)
로 부드러운 카드 모양을 만들었습니다.
3. 카드 내부 텍스트
Column
안 첫 줄은 통화 이름, 두 번째Row
에는 금액과 단위를 나란히 배치합니다.- 금액과 단위 사이에
SizedBox(width: 5)
로 적당한 간격을 둡니다.
시각화:
1 | Wallets View All |
🎨 화면 미리보기
1 | 카드 형태 컨테이너 안에 통화 정보가 정돈된 모습 |
📊 동작 흐름
1 | 1. Row가 섹션 제목과 View All 버튼을 좌우로 배치 |
✅ 체크리스트
- Wallets 제목과 View All이 같은 라인에 정렬되는가?
- 카드 배경색이 메인 배경보다 밝게 표시되는가?
- 금액과 통화 코드가 한 줄에 나란히 보이는가?
💡 연습 과제
- 다른 통화를 하나 더 추가하고 카드 아래에 배치해보세요.
- 카드 배경색을 살짝 더 밝은 회색으로 바꿔 대비를 실험해보세요.
View All
텍스트를 버튼으로 만들고 onPressed 콜백을 준비해보세요.
아이콘 배치와 Transform 활용
🎯 이번 단계에서 배울 것
clipBehavior: Clip.hardEdge
로 자식이 카드 바깥으로 넘치지 않게 하기Transform.scale
,Transform.translate
를 조합해 아이콘 위치와 크기 조정하기- 머티리얼 아이콘(
Icons.euro_rounded
)을 활용해 시각적 포인트 주기
📂 파일 구조
1 | 수정되는 파일 |
📝 1단계: 카드에 통화 아이콘 얹기
1 | Container( |
🔍 코드 상세 설명
1. Clip 설정
clipBehavior: Clip.hardEdge
로 둥근 둥근 모서리 밖으로 아이콘이 튀어나오지 않게 자릅니다.
2. Transform 두 번 중첩
Transform.scale
로 아이콘을 2.2배 확대합니다.- 내부에서
Transform.translate
를 적용해 살짝 왼쪽(-5)과 아래(+12)로 이동시킵니다. - WYSIWYG처럼 아이콘 위치를 세밀하게 조정할 수 있습니다.
3. 아이콘 스타일
size: 88
과 흰색을 사용해 어두운 배경 위에서 눈에 띄게 만듭니다.- 통화별로 대표 아이콘을 사용하면 직관적인 UI가 됩니다.
🎨 화면 미리보기
1 | ┌──────────────────────────────┐ |
📊 동작 흐름
1 | 1. Row가 텍스트와 아이콘을 양쪽 끝으로 분리 |
✅ 체크리스트
- 아이콘이 카드 밖으로 삐져나오지 않는가?
- 아이콘이 텍스트와 자연스럽게 맞춰졌는가?
- Transform 적용 순서(scale → translate)가 올바른가?
💡 연습 과제
- 아이콘 색상을
Colors.amber
로 바꿔 카드 강조 색을 실험해보세요. Transform.rotate
를 추가해 아이콘을 살짝 기울여 보세요.- 다른 통화 아이콘을 찾아 아이콘 데이터를 교체해보세요.
CurrencyCard 위젯과 스크롤 처리
🎯 이번 단계에서 배울 것
SingleChildScrollView
로 세로 레이아웃을 스크롤 가능하게 만들기- 카드 구성을
CurrencyCard
위젯으로 분리해 재사용성 극대화하기 isInverted
플래그로 밝은 카드/어두운 카드 테마 전환 구현하기Transform.translate
로 카드 간 겹쳐 보이게 오프셋 주기
📂 파일 구조
1 | 새로 생성되는 파일 |
📝 1단계: CurrencyCard 위젯 만들기
전체 코드 (lib/widgets/currency_card.dart @ 2.8):
1 | import 'package:flutter/material.dart'; |
🔍 코드 상세 설명
1. 테마 전환 플래그 isInverted
- 카드 배경과 텍스트, 아이콘 색을 조건문 없이 삼항 연산자로 깔끔히 바꿉니다.
- 밝은 카드와 어두운 카드를 동일한 위젯이 담당하게 되어 중복이 줄었습니다.
2. _blackColor
필드
- 반복적으로 사용하는 0xFF1F2123 색상을 필드로 빼 재사용합니다.
- 밑줄로 시작하는 변수명은 Dart에서 private(파일 내 전용)을 의미합니다.
3. 기존 Transform 로직 재사용
- 2.7에서 만든 아이콘 배치를 그대로 포함해 어느 카드에서나 적용됩니다.
📝 2단계: 스크롤 뷰와 카드 배치하기
핵심 변경 (lib/main.dart @ 2.8):
1 | body: SingleChildScrollView( |
SingleChildScrollView
로 긴 화면에서 overflow 에러 없이 세로 스크롤이 되도록 했습니다.Transform.translate
를 카드마다 적용해 살짝 겹치는 느낌의 스택 효과를 냅니다.- 두 번째 카드만
isInverted: true
를 사용해 흰색 카드 역색상을 보여줍니다.
🎨 화면 미리보기
1 | Euro Card |
📊 동작 흐름
1 | 1. SingleChildScrollView가 Column 전체를 스크롤 가능한 영역으로 감쌈 |
✅ 체크리스트
- 스크롤이 필요한 화면에서 overflow 에러가 사라졌는가?
- 세 가지 카드가 서로 다른 색/데이터로 표시되는가?
- Transform 덕분에 카드가 계단식으로 겹쳐 보이는가?
💡 연습 과제
isInverted
를 추가 카드에 적용하며 밝은/어두운 테마를 자유롭게 조합해보세요.Transform.translate
의 offset 값을 조절해 카드 겹침 간격을 바꿔보세요.CurrencyCard
에order
파라미터를 만들어 자동으로 높이 오프셋을 결정하도록 개선해보세요.
Code Challenge 반영
🎯 이번 단계에서 배울 것
- 마지막 카드 아이콘을 다른 머티리얼 아이콘으로 교체하기
- 작은 변경도 깃 커밋으로 남겨 추적 가능하게 만들기
📂 파일 구조
1 | 수정되는 파일 |
📝 1단계: Dollar 카드 아이콘 변경
1 | Transform.translate( |
Icons.attach_money_outlined
에서Icons.monetization_on_outlined
로 교체해 과제 요구사항을 반영했습니다.- 머티리얼 아이콘 라이브러리의 다양한 아이콘을 탐색하는 계기가 됩니다.
🎨 화면 미리보기
1 | Dollar 카드 아이콘이 세로 동전 그래픽으로 바뀐 모습 |
📊 동작 흐름
1 | 1. CurrencyCard가 새로운 아이콘 데이터를 전달받음 |
✅ 체크리스트
- Dollar 카드 아이콘이 바뀌었는가?
- 나머지 카드 레이아웃에는 영향이 없는가?
💡 연습 과제
- 다른 통화 카드도 각기 어울리는 아이콘으로 바꿔보세요.
- 아이콘 색상을 카드 테마와 다르게 줘서 시각적 대비를 확인하세요.
- 머티리얼 아이콘 사이트에서 즐겨 쓰는 아이콘을 찾아 목록을 정리해보세요.
📚 전체 흐름 정리
- 다크 테마 배경과 헤더가 완성되었습니다.
- 잔액 정보와 CTA 버튼을 추가하고 const로 렌더링을 최적화했습니다.
- 버튼을 별도 위젯으로 추출해 재사용성을 높였습니다.
- Wallets 섹션과 통화 카드, 아이콘 배치를 마무리했습니다.
- 카드 역시 컴포넌트화하고 스크롤 처리, 겹침 효과를 구현했습니다.
- 코드 챌린지에서는 아이콘 교체로 머티리얼 컴포넌트 탐색을 마쳤습니다.
✅ 최종 점검 리스트
- 헤더, 잔액, Wallets 섹션이 순서대로 화면에 배치되었는가?
- Button과 CurrencyCard 위젯이 각각
lib/widgets
폴더에 존재하는가? -
isInverted
가 카드 색상 테마를 잘 전환하고 있는가? - 스크롤이 필요한 경우
SingleChildScrollView
가 적용되어 있는가? - 최종 아이콘 교체가 반영되었는가?