Flutter

[Flutter] Flutter Widgets (플러터 위젯) 종류 & 사용법 🗂️

벡연 2025. 3. 28. 00:52

 

 

위젯 종류 간단 정리
레이아웃 위젯 (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가지로 나뉨

  1. Asset 이미지: 앱 내 로컬 파일 사용
  2. Network 이미지: 인터넷 주소에서 불러옴
  3. 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: () {},
      );
    },
  ),
)

빠이 (´▽`ʃ♡ƪ)