일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 에뮬레이터
- NaverMap
- flutter 위젯 종류
- 플러터 위젯
- flutter
- 네이버 지도 api
- Android Studio
- flutter doctor
- flutter 위젯
- flutter widgets
- 플러터
- 플러터 지도
- 플러터 설치
- AVD
- 환경 변수 설정
- java
- 안드로이드 스튜디오 설치
- flutter style
- 환경 변수
- 네이버 지도
- 레이아웃 위젯
- flutter_naver_map
- dart
- Flutter 설치
- 안드로이드스튜디오
- JavaScript
- Today
- Total
벡연
[Flutter] Flutter Widgets (플러터 위젯) 종류 & 사용법 🗂️ 본문
위젯 종류 간단 정리
레이아웃 위젯 (Layout Widgets) | 다른 위젯의 배치를 결정하는 역할 |
기본 위젯 (Basic Widgets) | 기본적인 정보를 화면에 표시할 때 사용 |
버튼 위젯 (Button Widgets) | 사용자의 클릭 등 인터랙션을 처리할 때 사용 |
입력 위젯 (Input Widgets) | 사용자의 텍스트 및 값 입력을 처리하는 위젯 |
스크롤 위젯 (Scrollable Widgets) | 스크롤 가능한 리스트와 그리드를 구현 |
컨테이너 위젯 (Container Widgets) | 화면에서 공간을 확보하거나 스타일을 지정 |
네비게이션 위젯 (Navigation Widgets) | 화면 간 이동이나 앱 내 탐색을 구현할 때 사용 |
상태 표시 위젯 (Progress Widgets) | 로딩, 진행 상황 표시할 때 사용 |
상호작용 위젯 (Interactive Widgets) | 사용자와의 터치 및 상호작용을 다룰 때 사용 |
테마와 스타일 위젯 (Theme Widgets) | 앱 전체의 스타일 및 테마를 관리 |
📂 레이아웃 위젯 (Layout Widgets)
- Column: 세로 방향 배치
- Row: 가로 방향 배치
- Stack: 위젯 겹쳐서 배치
- Expanded: 사용 가능한 공간을 채움
- SizedBox: 크기 제한 지정
✏️ Column 위젯 (세로 배치)
- mainAxisAlignment : 세로 방향 (메인축) 정렬
- crossAxisAlignment : 가로 방향 (교차축) 정렬
📍 mainAxisAlignment 옵션
mainAxisAlignment | 설명 |
.start | 위쪽 정렬 |
.center | 중앙 정렬 |
.end | 아래쪽 정렬 |
.spaceBetween |
위아래 끝에 붙이고 사이 간격 동일하게
|
.spaceEvenly | 모든 간격 동일 |
.spaceAround | 끝쪽 간격보다 위젯 사이 간격을 2배 더 넓게 |
📍 crossAxisAlignment 옵션
crossAxisAlignment | 설명 |
.start | 왼쪽 정렬 |
.center | 가운데 정렬 |
.end | 오른쪽 정렬 |
. stretch |
위젯을 좌우로 꽉 채움
|
[ 예시 ]
// Column
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, // 세로축 정렬 (위에서 아래로)
crossAxisAlignment: CrossAxisAlignment.center, // 가로축 정렬 (좌우)
children: [
Container(width: 100, height: 50, color: Colors.red),
Container(width: 100, height: 50, color: Colors.green),
Container(width: 100, height: 50, color: Colors.blue),
],
)
=> 빨강, 초록, 파랑 컨테이너가 세로로 동일한 간격으로 배치되고, 가운데 정렬
💡 언제 사용하면 좋을까 ?
- 버튼이나 텍스트를 화면 가운데로 정렬할 때 !
✏️ Row 위젯 (가로 배치)
- mainAxisAlignment : 가로 방향 (메인축) 정렬
- crossAxisAlignment : 세로 방향 (교차축) 정렬
📍 crossAxisAlignment 옵션
mainAxisAlignment | 설명 |
.start | 왼쪽 정렬 |
.center | 가운데 정렬 |
.end | 오른쪽 정렬 |
.spaceBetween | 양끝 붙이고 동일 간격 |
.spaceEvenly | 모두 동일 간격 |
.spaceAround | 끝 간격의 2배씩 가운데 간격 |
📍 mainAxisAlignment 옵션
crossAxisAlignment | 설명 |
.start | 위쪽 정렬 |
.center | 세로축 가운데 정렬 |
.end | 아래쪽 정렬 |
. stretch | 위젯 높이를 위아래 꽉 채움 |
[ 예시 ]
// Row
Row(
mainAxisAlignment: MainAxisAlignment.center, // 가로축 정렬 (좌우)
crossAxisAlignment: CrossAxisAlignment.center, // 세로축 정렬 (위아래)
children: [
Container(width: 100, height: 50, color: Colors.red),
Container(width: 100, height: 50, color: Colors.green),
Container(width: 100, height: 50, color: Colors.blue),
],
),
=> 컨테이너 3개가 양 끝과 가운데 간격 동일하게 가로로 배치되고, 높이가 다른 컨테이너들의 아래쪽이 정렬
💡 언제 사용하면 좋을까 ?
- 리스트의 항목을 화면 양 끝으로 정렬할 때 !
- 가로로 배치된 버튼들을 동일한 간격으로 나열할 때 !
✏️ Stack 위젯
- alignment: 겹친 위젯의 정렬방향 지정 (기본은 왼쪽 위)
- clipBehavior: 위젯이 넘칠 때 처리 방법 지정 (Clip.none 이 기본)
[ 예시 ]
// Stack
Stack(
alignment: Alignment.center,
children: [
Container(width: 200, height: 200, color: Colors.blue),
Container(width: 150, height: 150, color: Colors.red),
Positioned( // 특정 위치 지정
bottom: 10,
right: 10,
child: Container(width: 50, height: 50, color: Colors.yellow),
),
],
)
💡 언제 사용하면 좋을까 ?
- 프로필 이미지 위에 뱃지 띄울 때 !
- 이미지 위에 텍스트 올릴 때 !
- 앱 내 알림 배지를 표현할 때 !
✏️ Expanded 위젯
- 주로 Row, Column 안에서 사용
- 사용 가능한 공간을 나눠서 꽉 채우도록 위젯을 확장
- flex 속성으로 확장 비율을 정할 수 있음 ( 기본은 flex: 1 )
[ 예시 ]
// 기본 예시
Row(
children: [
Container(width: 50, height: 50, color: Colors.red),
Expanded( // 남은 모든 공간 차지
child: Container(height: 50, color: Colors.green),
),
Container(width: 50, height: 50, color: Colors.blue),
],
)
=> 가운데 녹색 컨테이너가 남은 공간을 전부 채움
// flex 속성 예시
Column(
children: [
Expanded(flex: 1, child: Container(color: Colors.red)),
Expanded(flex: 2, child: Container(color: Colors.green)),
Expanded(flex: 3, child: Container(color: Colors.blue)),
],
)
=> 비율대로 빨강(1) : 초록(2) : 파랑(3)의 비율로 확장
💡 언제 사용하면 좋을까 ?
- 화면을 일정한 비율로 나누고 싶을 때 !
- 위젯의 크기를 동적으로 채우고 싶을 때 !
- 반응형 UI를 쉽게 구현할 때 !
✏️ SizedBox 위젯
- width, height 속성으로 크기를 지정
- 자식(child)을 하나만 가질 수 있음
- 크기만 지정하고 자식을 넣지 않으면 빈 공간으로서의 간격으로 쓰여짐
[ 예시 ]
// 간격만 만들 때 (아주 많이 사용)
Column(
children: [
Container(width: 100, height: 50, color: Colors.red),
SizedBox(height: 20), // 위젯 사이의 간격을 20만큼 줌
Container(width: 100, height: 50, color: Colors.green),
],
)
// 위젯 크기 고정
SizedBox(
width: 100,
height: 100,
child: ElevatedButton(
child: Text("버튼"),
onPressed: () {},
),
)
=> 이 버튼은 항상 100x100 크기로 고정 됨
// 무한 크기 지정 (가로 세로 꽉 채우기)
SizedBox.expand(
child: Container(color: Colors.blue),
)
=> 전체 영역을 파란색으로 채움
💡 언제 사용하면 좋을까 ?
- 위젯 간 일정한 간격 줄 때 !
- 버튼이나 입력창의 크기 고정할 때 !
- 특정 크기로 제한하고 싶을 때 !
☝🏻 Expanded와 SizedBox의 차이는 ?
Expanded | SizedBox | |
남는 공간을 모두 차지 하거나 나눠서 사용 | 공간을 정확한 크기(픽셀)로만 제한하거나 확보할 때 사용 |
📂 기본 위젯 (Basic Widgets)
- Text : 텍스트 출력
- Icon : 아이콘 출력
- Image : 이미지 출력
✏️ Text 위젯
- data (필수): 보여줄 텍스트
- style : 폰트 크기, 색상, 두께, 스타일 등 지정
- textAlign : 텍스트의 정렬(가운데, 왼쪽, 오른쪽 등)
- maxLines : 텍스트의 최대 라인 수 제한
- overflow : 텍스트가 넘칠 때 처리 방법 지정
[ 예시 ]
// 기본 사용법
Text(
"안녕하세요, Flutter!",
style: TextStyle(
fontSize: 20, // 글씨 크기
color: Colors.blue, // 글씨 색상
fontWeight: FontWeight.bold, // 두께
),
)
// 응용 사용법
Text(
"Flutter는 Google이 만든 오픈소스 UI 프레임워크입니다. 멀티 플랫폼 앱을 만들 수 있죠!",
maxLines: 2, // 최대 2줄로 제한
overflow: TextOverflow.ellipsis, // 넘치는 글자 (...) 처리
textAlign: TextAlign.center, // 가운데 정렬
)
📍 style 속성의 TextStyle 옵션
속성 | 설명 | 예시 |
fontSize | 글자 크기 | fontSize: 16 |
color | 글자 색상 | color: Colors.black |
fontWeight | 글자 두께 | FontWeight.bold |
fontStyle | 글자 스타일 | FontStyle.italic |
decoration | 글자 꾸미기 | underline, lineThrough |
✏️ Icon 위젯
https://fonts.google.com/icons
Material Symbols and Icons - Google Fonts
Material Symbols are our newest icons consolidating over 2,500 glyphs in a single font file with a wide range of design variants.
fonts.google.com
- Flutter는 기본적으로 Material Icons을 지원
- icon (필수): 아이콘 이름
- size: 아이콘 크기
- color: 아이콘 색
[ 예시 ]
// 기본 사용법
Icon(
Icons.favorite, // 하트 모양 아이콘
size: 50,
color: Colors.red,
)
// 다양한 아이콘
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Icon(Icons.home, size: 40, color: Colors.blue),
Icon(Icons.email, size: 40, color: Colors.green),
Icon(Icons.settings, size: 40, color: Colors.grey),
],
)
// 아이콘에 클릭 이벤트가 필요할 때
IconButton(
icon: Icon(Icons.add),
color: Colors.blue,
iconSize: 40,
onPressed: () {
print("아이콘 버튼 클릭!");
},
)
✏️ Image 위젯
☝🏻 이미지 소스는 크게 3가지로 나뉨
- Asset 이미지: 앱 내 로컬 파일 사용
- Network 이미지: 인터넷 주소에서 불러옴
- File 이미지: 기기 내 저장소에서 불러옴
- width, height : 이미지의 가로/세로 크기 지정
- fit : 이미지가 위젯 내에서 표시될 때 크기 조정 방식
- alignment : 이미지의 정렬 방향 지정
💡Asset 이미지 (로컬 파일)
[ pubspec.yaml ]
flutter:
assets:
- assets/images/
[ 예시 ]
Image.asset(
'assets/images/example.png',
width: 100,
height: 100,
fit: BoxFit.cover, // 위젯 크기에 맞추어 이미지 꽉 채움
)
💡네트워크 이미지 (웹 URL)
[ 예시 ]
Image.network(
'https://example.com/flutter.jpg',
width: 200,
height: 150,
fit: BoxFit.contain, // 비율 유지하며 위젯 안에 꽉 채움
)
💡파일 이미지 (기기 로컬 파일)
[ 예시 ]
import 'dart:io';
Image.file(
File('/storage/emulated/0/Download/my_image.jpg'),
width: 100,
height: 100,
)
📍 Image의 fit 속성
BoxFit 속성 | 설명 |
.cover | 이미지가 위젯을 꽉 채우도록 비율 유지하며 잘림 |
.contain | 이미지 비율 유지하며 위젯 내부에 맞춤 |
.fill | 이미지가 위젯 크기와 동일하게 비율 무시하고 늘어남 |
.fitWidth | 가로폭만 위젯과 동일하게 맞춤 |
.fitHeight | 세로높이만 위젯과 동일하게 맞춤 |
📂 버튼 위젯 (Button Widgets)
- ElevatedButton: 기본 버튼
- TextButton: 글자만 표시되는 버튼
- OutlinedButton: 테두리만 있는 버튼
- IconButton: 아이콘 버튼
- FloatingActionButton: 플로팅 액션 버튼
✏️ ElevatedButton 위젯
[ 예시 ]
ElevatedButton(
child: Text('Elevated Button'),
style: ElevatedButton.styleFrom(
primary: Colors.blue, // 배경색
onPrimary: Colors.white, // 글자색
elevation: 5, // 그림자 깊이
),
onPressed: () {
print('Elevated 버튼 클릭!');
},
)
✏️ TextButton 위젯
[ 예시 ]
TextButton(
child: Text('Text Button'),
style: TextButton.styleFrom(
primary: Colors.green, // 글자색
),
onPressed: () {
print('Text 버튼 클릭!');
},
)
✏️ OutlinedButton 위젯
[ 예시 ]
OutlinedButton(
child: Text('Outlined Button'),
style: OutlinedButton.styleFrom(
primary: Colors.orange, // 글자색
side: BorderSide(color: Colors.orange, width: 2), // 테두리 설정
),
onPressed: () {
print('Outlined 버튼 클릭!');
},
)
✏️ IconButton 위젯
[ 예시 ]
IconButton(
icon: Icon(Icons.favorite),
color: Colors.red,
iconSize: 30,
onPressed: () {
print('아이콘 버튼 클릭!');
},
)
✏️ FloatingActionButton (FAB) 위젯
[ 예시 ]
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
backgroundColor: Colors.purple,
onPressed: () {
print('FAB 버튼 눌림!');
},
),
📍Button 위젯에 사용되는 styleFrom 옵션
옵션 | 설명 | 사용 예 |
backgroundColor | 버튼의 배경색 | backgroundColor: Colors.blue |
foregroundColor | 버튼 안의 글자 및 아이콘 색상 | foregroundColor: Colors.white |
onSurface | 버튼 비활성화(disabled) 시 색상 | onSurface: Colors.grey |
shadowColor | 버튼 그림자 색상 | shadowColor: Colors.black54 |
elevation | 버튼의 그림자 깊이 (입체감) | elevation: 5 |
padding | 버튼 내부의 여백 지정 | padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10) |
minimumSize | 버튼의 최소 크기 지정 | minimumSize: Size(100, 50) |
fixedSize | 버튼의 고정 크기 지정 | fixedSize: Size(200, 60) |
maximumSize | 버튼의 최대 크기 지정 | maximumSize: Size(300, 100) |
side | 버튼의 테두리 색상과 두께 지정 | side: BorderSide(color: Colors.red, width: 2) |
shape | 버튼의 외곽 형태(둥글게 처리 등) 지정 | shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)) |
alignment | 버튼 내부 자식의 정렬 방향 | alignment: Alignment.centerLeft |
textStyle | 버튼의 텍스트 스타일 설정 | textStyle: TextStyle(fontSize: 18, fontWeight: FontWeight.bold) |
animationDuration | 버튼 스타일 변경 시 애니메이션 시간 | animationDuration: Duration(milliseconds: 500) |
tapTargetSize | 버튼 터치 영역 크기 설정 | tapTargetSize: MaterialTapTargetSize.shrinkWrap |
visualDensity | 버튼의 밀도 조정(더 촘촘히 배치 등) | visualDensity: VisualDensity.compact |
enableFeedback | 버튼 클릭 시 진동, 소리 등 피드백 여부 | enableFeedback: false |
📂 입력 위젯 (Input Widgets)
- TextField: 텍스트 입력창
- Checkbox: 체크박스
- Radio: 라디오 버튼
- Switch: On/Off 스위치
- Slider: 슬라이더
✏️ TextField 위젯
- decoration: 입력창의 힌트, 라벨, 테두리 등 설정
- controller: 입력된 텍스트 관리
- keyboardType: 키보드 타입 지정
- obscureText: 비밀번호 입력 시 글자를 숨김 처리
[ 예시 ]
// 기본 사용법
TextField(
decoration: InputDecoration(
labelText: "이름",
hintText: "이름을 입력하세요",
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.person),
),
)
// 입력값 관리 (TextEditingController)
final controller = TextEditingController();
TextField(
controller: controller,
decoration: InputDecoration(labelText: "이메일"),
);
// 값 가져오기
print(controller.text);
// 숫자 입력만 받을 때
TextField(
keyboardType: TextInputType.number,
decoration: InputDecoration(labelText: "나이"),
)
// 비밀번호 입력 (숨김 처리)
TextField(
obscureText: true,
decoration: InputDecoration(labelText: "비밀번호"),
)
☝🏻 입력창에 입력 제한을 둘 수 있나요 ?
TextField(
inputFormatters: [
LengthLimitingTextInputFormatter(10), // 최대 10자 제한
],
)
☝🏻 입력 완료 후 키보드를 닫을 수 있나요 ?
FocusScope.of(context).unfocus();
✏️ Checkbox 위젯
[ 예시 ]
// 기본 사용법
bool isChecked = false;
Checkbox(
value: isChecked,
onChanged: (bool? value) {
setState(() {
isChecked = value!;
});
},
)
// 체크박스 + 텍스트 함께 사용할 때 (CheckboxListTile)
bool isChecked = false;
CheckboxListTile(
title: Text("이용약관 동의"),
value: isChecked,
onChanged: (bool? value) {
setState(() {
isChecked = value!;
});
},
controlAffinity: ListTileControlAffinity.leading, // 체크박스 왼쪽 배치
)
✏️ Radio 위젯
- groupValue로 같은 그룹에 속한 라디오 버튼을 연결
[ 예시 ]
// 기본 사용법
String selectedGender = '남자';
Column(
children: [
RadioListTile<String>(
title: Text("남자"),
value: "남자",
groupValue: selectedGender,
onChanged: (value) {
setState(() {
selectedGender = value!;
});
},
),
RadioListTile<String>(
title: Text("여자"),
value: "여자",
groupValue: selectedGender,
onChanged: (value) {
setState(() {
selectedGender = value!;
});
},
),
],
)
✏️ Switch 위젯
[ 예시 ]
// 기본 사용법
bool isOn = false;
Switch(
value: isOn,
onChanged: (bool value) {
setState(() {
isOn = value;
});
},
)
// 스위치 + 텍스트 함께 사용할 때 (SwitchListTile)
bool notificationOn = true;
SwitchListTile(
title: Text("알림 설정"),
value: notificationOn,
onChanged: (bool value) {
setState(() {
notificationOn = value;
});
},
activeColor: Colors.green,
)
✏️ Slider 위젯
- divisions: 슬라이더 구간을 나눠서 스냅을 만들어줍니다.
- label: 값을 보여주는 레이블입니다.
[ 예시 ]
// 기본 사용법
double sliderValue = 50;
Slider(
value: sliderValue,
min: 0,
max: 100,
divisions: 10,
label: sliderValue.round().toString(),
onChanged: (double value) {
setState(() {
sliderValue = value;
});
},
)
📂 스크롤 위젯 (Scrollable Widgets)
- SingleChildScrollView: 하나의 자식을 스크롤 가능하게 만듦
- ListView: 리스트 스크롤
- GridView: 그리드 스크롤
- PageView: 페이지 스크롤
✏️ SingleChildScrollView 위젯
- 단일 자식을 스크롤 가능하게 함
- 콘텐츠가 많아서 화면을 초과할 때만 사용
[ 예시 ]
// 기본 사용법
SingleChildScrollView(
child: Column(
children: List.generate(
20,
(index) => Container(
height: 80,
color: Colors.primaries[index % Colors.primaries.length],
),
),
),
)
💡 언제 사용하면 좋을까 ?
- 간단한 콘텐츠가 넘칠 때 (회원가입 화면, 상세 페이지 등) !
- 한 방향(세로 또는 가로) 스크롤이 필요할 때 !
✏️ ListView 위젯 ( 가장 많이 사용 )
- 목록 형태의 콘텐츠를 스크롤 가능하게 보여줄 때 사용
- 아이템 수가 많을 때 성능 최적화를 자동으로 처리
[ 예시 ]
// 기본 사용법 (ListView.builder 방식, 권장)
ListView.builder(
itemCount: 100,
itemBuilder: (context, index) {
return ListTile(
leading: Icon(Icons.person),
title: Text("사용자 $index"),
);
},
)
// 고정 아이템 개수 (ListView 기본 방식)
ListView(
children: [
ListTile(title: Text("항목 1")),
ListTile(title: Text("항목 2")),
ListTile(title: Text("항목 3")),
],
)
// 리스트 구분선 (ListView.separated 방식)
ListView.separated(
itemCount: 20,
itemBuilder: (context, index) => ListTile(title: Text("항목 $index")),
separatorBuilder: (context, index) => Divider(), // 구분선 추가
)
☝🏻 스크롤 방향을 변경할 수 있나요? ( 모든 스크롤 위젯에서 scrollDirection 옵션 사용 )
ListView.builder(
scrollDirection: Axis.horizontal, // 가로로 스크롤
itemBuilder: (context, index) => Container(width: 100, color: Colors.red),
)
☝🏻 스크롤바 표시할 수 있나요 ?
Scrollbar(
child: ListView.builder(
itemBuilder: (context, index) => ListTile(title: Text("항목 $index")),
),
)
☝🏻 스크롤 위치를 관리할 수 있나요 ?
final ScrollController _controller = ScrollController();
ListView(
controller: _controller,
)
// 스크롤 맨 위로 이동하기
_controller.jumpTo(0);
💡 언제 사용하면 좋을까 ?
- 채팅 목록, 연락처 목록, 피드 등 많은 항목을 스크롤로 처리할 때 !
- 동적으로 항목이 많아지거나, 무한 스크롤 구현할 때 (ListView.builder 필수) !
✏️ GridView 위젯
- 격자(Grid) 형태로 항목을 나열할 때 사용
[ 예시 ]
// 기본 사용법 (GridView.builder, 권장)
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, // 한 줄에 2개씩 배치
crossAxisSpacing: 10, // 가로 간격
mainAxisSpacing: 10, // 세로 간격
),
itemCount: 20,
itemBuilder: (context, index) {
return Container(
color: Colors.amber,
child: Center(child: Text("항목 $index")),
);
},
)
// 고정 개수 (GridView.count 방식)
GridView.count(
crossAxisCount: 3,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
children: List.generate(
20,
(index) => Container(color: Colors.blue),
),
)
💡 언제 사용하면 좋을까 ?
- 이미지 갤러리, 쇼핑몰 상품 리스트 등 격자형 콘텐츠 !
- 콘텐츠를 일정하게 정리된 레이아웃으로 배치할 때 !
✏️ PageView 위젯
- 좌우 또는 상하로 페이지처럼 넘기면서 콘텐츠를 보여줄 때 사용
[ 예시 ]
// 기본 사용법
PageView(
children: [
Container(color: Colors.red),
Container(color: Colors.green),
Container(color: Colors.blue),
],
)
// 페이지 전환 감지하기 (PageController 사용)
final PageController controller = PageController();
PageView(
controller: controller,
onPageChanged: (index) {
print("현재 페이지: $index");
},
children: [
Container(color: Colors.red),
Container(color: Colors.green),
Container(color: Colors.blue),
],
)
💡 언제 사용하면 좋을까 ?
- 온보딩 화면, 이미지 슬라이드쇼 !
- 페이지 단위로 콘텐츠를 보여줘야 할 때 !
📂 컨테이너 위젯 (Container Widgets)
- Container: 스타일 및 공간 확보
- Card: 그림자 카드형 UI
- Padding: 패딩 추가
- Center: 자식 위젯을 화면 중앙에 배치
✏️ Container 위젯
- Flutter에서 가장 기본이면서도 가장 많이 사용하는 위젯
- 다른 위젯을 감싸고 스타일링(색상, 패딩, 여백 등)을 지정할 때 사용
- color와 decoration은 같이 사용할 수 없으며, 둘 중 하나만 사용
[ 예시 ]
// 기본 사용법
Container(
width: 200,
height: 100,
padding: EdgeInsets.all(20),
margin: EdgeInsets.symmetric(vertical: 10),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(15), // 둥근 모서리
boxShadow: [
BoxShadow(
color: Colors.black26,
blurRadius: 5,
offset: Offset(0, 3), // 그림자 방향
),
],
),
child: Text("컨테이너 위젯", style: TextStyle(color: Colors.white)),
)
📍 Container 속성
속성 | 설명 |
width, height | 크기 지정 |
padding | 내부 여백 |
margin | 외부 여백 |
color | 배경 색상 |
decoration |
테두리, 그림자, 그라데이션 등 스타일링 |
alignment | 자식 위젯 정렬 |
✏️ Padding 위젯
- 자식 위젯과 부모 위젯 사이에만 영향을 주며, 크기나 색상 등 다른 옵션 없음
- 여백을 줄 때는 Container 대신 Padding을 쓰는 것이 권장 됨
[ 예시 ]
// 기본 사용법
Padding(
padding: EdgeInsets.all(16), // 모든 방향 여백
child: Text("여백 있는 텍스트"),
)
✏️ Center 위젯
- 위젯을 정확히 정중앙으로 배치할 때 간단히 사용
[ 예시 ]
// 기본 사용법
Center(
child: Container(width: 100, height: 100, color: Colors.red),
)
✏️ Card 위젯
- elevation: 그림자 깊이 조절
- shape: 카드 모서리 스타일링
- color: 카드 배경 색상
- margin: 외부 여백 지정
[ 예시 ]
// 기본 사용법
Card(
elevation: 5, // 그림자 깊이
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
child: Padding(
padding: EdgeInsets.all(16),
child: Text("이것은 카드 위젯입니다."),
),
)
☝🏻 여백만 필요 vs 스타일링 필요
// 여백만 필요 → Padding 추천
Padding(
padding: EdgeInsets.all(10),
child: Text("텍스트"),
)
// 스타일링 필요 → Container 사용
Container(
padding: EdgeInsets.all(10),
color: Colors.blue,
child: Text("텍스트"),
)
☝🏻 Container에 크기를 지정하지 않으면 어떻게 되나요 ?
=> 컨테이너에 크기를 지정하지 않으면 자식 위젯 크기에 따라 자동으로 조정 됨
Container(
color: Colors.amber,
child: Text("자식 크기에 맞춤"),
)
☝🏻 Container에 배경 이미지를 넣고 싶으면 ?
Container(
width: 300,
height: 200,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/background.jpg"),
fit: BoxFit.cover,
),
),
)
📂 네비게이션 위젯 (Navigation Widgets)
- Navigator: 화면 간 이동을 처리하는 가장 중요한 클래스
- AppBar: 앱의 헤더
- BottomNavigationBar: 앱의 푸터
- TabBar & TabBarView: 화면 상단에서 여러 탭으로 전환되는 화면 구성 시 사용
- Drawer: 앱의 좌측 또는 우측에서 화면을 슬라이드해서 나타나는 메뉴
✏️ Navigator 위젯
- 화면을 스택(Stack) 구조로 관리
- push/pop 메서드로 화면 이동
[ 예시 ]
// 새 화면으로 이동 (push)
Navigator.push(
context,
MaterialPageRoute(builder: (context) => NewScreen()),
);
// 현재 화면 종료 (pop)
Navigator.pop(context);
// 이동한 화면에 데이터 전달 및 받기
# 화면 이동 시 데이터 전달
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NewScreen(data: '전달할 데이터'),
),
);
# 이동한 화면에서 데이터 받기
class NewScreen extends StatelessWidget {
final String data;
NewScreen({required this.data});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: Text(data)),
);
}
}
// 화면 이동 후 돌아올 때 결과 값 가져오기
# 화면 이동할 때
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => NewScreen()),
);
print("받은 결과값: $result");
# 이동한 화면에서 결과값 반환할 때
Navigator.pop(context, '결과값입니다');
✏️ AppBar 위젯
- 화면 상단에 나타나는 앱의 헤더를 표현
- 일반적으로 타이틀, 뒤로 가기 버튼, 메뉴 아이콘을 표시
[ 예시 ]
Scaffold(
appBar: AppBar(
title: Text('화면 타이틀'),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
Navigator.pop(context);
},
),
actions: [
IconButton(
icon: Icon(Icons.settings),
onPressed: () {},
),
],
),
body: Container(),
)
📍AppBar 주요 속성
속성 | 설명 |
title | 화면 제목 |
leading | 좌측 아이콘 (뒤로 가기 등) |
actions | 우측 아이콘 메뉴 |
backgroundColor | 배경 색상 지정 |
✏️ BottomNavigationBar 위젯
- 화면 하단에서 여러 개의 탭으로 빠르게 화면을 전환할 때 사용
[ 예시 ]
// 기본 사용법
int _selectedIndex = 0;
Scaffold(
body: IndexedStack(
index: _selectedIndex,
children: [
HomeScreen(),
SearchScreen(),
SettingScreen(),
],
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _selectedIndex,
onTap: (int index) {
setState(() {
_selectedIndex = index;
});
},
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), label: "홈"),
BottomNavigationBarItem(icon: Icon(Icons.search), label: "검색"),
BottomNavigationBarItem(icon: Icon(Icons.settings), label: "설정"),
],
),
)
📍주요 속성
속성 | 설명 |
items | 탭 아이템 설정 |
currentIndex | 현재 선택된 탭 인덱스 |
onTap | 탭 선택 시 동작 |
✏️ TabBar & TabBarView 위젯
- 화면 상단에서 여러 탭으로 전환되는 화면 구성 시 사용
- 반드시 탭 수 (length)와 화면 수가 같아야 함
[ 예시 ]
// 기본 사용법 (DefaultTabController 사용)
DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.directions_car), text: "자동차"),
Tab(icon: Icon(Icons.directions_transit), text: "대중교통"),
Tab(icon: Icon(Icons.directions_bike), text: "자전거"),
],
),
title: Text('탭 화면'),
),
body: TabBarView(
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
),
),
)
✏️ Drawer 위젯
- 앱의 좌측 또는 우측에서 화면을 슬라이드해서 나타나는 메뉴를 구성할 때 사용
[ 예시 ]
// 기본 사용법
Scaffold(
appBar: AppBar(title: Text("Drawer 예시")),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
DrawerHeader(
decoration: BoxDecoration(color: Colors.blue),
child: Text("메뉴 헤더", style: TextStyle(color: Colors.white, fontSize: 24)),
),
ListTile(
leading: Icon(Icons.message),
title: Text("메시지"),
onTap: () {},
),
ListTile(
leading: Icon(Icons.account_circle),
title: Text("프로필"),
onTap: () {},
),
],
),
),
body: Center(child: Text("Drawer 메뉴 화면")),
)
📂 상태 표시 위젯 (Progress Widgets)
- CircularProgressIndicator (원형 로딩)
- LinearProgressIndicator (선형 로딩)
✏️ CircularProgressIndicator 위젯
[ 예시 ]
SizedBox(
width: 50,
height: 50,
child: CircularProgressIndicator(
strokeWidth: 5, // 두께
valueColor: AlwaysStoppedAnimation<Color>(Colors.blue), // 색상
),
)
✏️ LinearProgressIndicator 위젯
[ 예시 ]
LinearProgressIndicator(
value: 0.7, // 70% 진행
backgroundColor: Colors.grey[300],
color: Colors.green,
)
☝🏻 로딩 인디케이터 크기는 어떻게 변경하나요 ?
=> SizedBox 위젯으로 감싸면 크기 조절이 가능합니다 !
SizedBox(width: 30, height: 30, child: CircularProgressIndicator())
📂 상호작용 위젯 (Interactive Widgets)
- GestureDetector
- InkWell
- Dismissible
✏️ GestureDetector 위젯
- 다양한 제스처(탭, 더블 탭, 길게 누르기 등)를 처리
[ 예시 ]
// 기본 사용법
GestureDetector(
onTap: () {
print("위젯이 탭 되었어요!");
},
onDoubleTap: () {
print("더블탭!");
},
onLongPress: () {
print("길게 누르기!");
},
child: Container(
width: 100,
height: 100,
color: Colors.amber,
),
)
✏️ InkWell 위젯
- Material 디자인의 터치 효과를 제공
- 터치 시 물결 효과
- 반드시 Material 위젯 내에서 사용해야 물결 효과가 나타남
[ 예시 ]
// 기본 사용법
Material(
child: InkWell(
onTap: () {
print("InkWell 클릭!");
},
child: Container(
width: 100,
height: 50,
alignment: Alignment.center,
child: Text("터치하세요"),
),
),
)
✏️ Dismissible 위젯
- 항목을 좌우로 슬라이드해 제거할 때 사용
[ 예시 ]
// 기본 사용법
List<String> items = ["항목1", "항목2", "항목3"];
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
return Dismissible(
key: Key(item),
onDismissed: (direction) {
setState(() {
items.removeAt(index);
});
},
background: Container(color: Colors.red),
child: ListTile(title: Text(item)),
);
},
)
📂 테마와 스타일 위젯 (Theme Widgets)
- MaterialApp
- Theme & ThemeData
✏️ MaterialApp 위젯
- MaterialApp 내의 theme 속성을 사용하여 기본 스타일을 적용
- 앱 전체 테마 설정
[ 예시 ]
// 기본 사용법
MaterialApp(
theme: ThemeData(
primaryColor: Colors.blue,
accentColor: Colors.amber,
scaffoldBackgroundColor: Colors.white,
fontFamily: 'NotoSansKR',
textTheme: TextTheme(
headline1: TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
bodyText2: TextStyle(fontSize: 16),
),
),
home: MyHomeScreen(),
)
// Theme로 특정 위젯 영역의 스타일 덮어쓰기 (부분적으로 스타일을 변경할 때 사용)
Theme(
data: Theme.of(context).copyWith(
primaryColor: Colors.red,
),
child: Builder(
builder: (context) {
return ElevatedButton(
child: Text("테마 버튼"),
onPressed: () {},
);
},
),
)
빠이 (´▽`ʃ♡ƪ)
'Flutter' 카테고리의 다른 글
[Flutter] Flutter란❓ (0) | 2025.03.27 |
---|---|
[Flutter] 네이버 지도 API key 발급 및 지도 표출 🗺️ (0) | 2025.03.22 |
[Flutter & Android Studio] 플러터 및 안드로이드 스튜디오 다운로드 및 개발 환경 셋팅 🔎 (0) | 2025.03.19 |