Flutter 튜토리얼 5편: Material과 Cupertino 위젯

요약#

핵심 요지#

  • 문제 정의: Android와 iOS 사용자는 각 플랫폼에 익숙한 UI를 기대한다.
  • 핵심 주장: Flutter는 Material Design1Cupertino2 두 가지 디자인 시스템을 제공한다.
  • 주요 근거: Material은 Android 스타일, Cupertino는 iOS 스타일의 위젯을 각각 제공하여 플랫폼에 맞는 UX를 구현할 수 있다.
  • 실무 기준: 대부분의 앱은 Material Design을 기본으로 사용하고, iOS 네이티브 경험이 중요하면 Cupertino를 활용한다.
  • 한계: 두 시스템을 혼용하면 코드가 복잡해질 수 있다.

문서가 설명하는 범위#

  • Material Design 3의 핵심 개념과 주요 위젯
  • Cupertino 디자인의 특징과 주요 위젯
  • 플랫폼별 위젯 선택 전략

읽는 시간: 14분 | 난이도: 초급


참고 자료#


문제 상황#

크로스플랫폼 앱을 만들 때 한 가지 디자인만 사용하면 어떻게 될까요?
특정 플랫폼 사용자에게 어색한 경험을 줄 수 있습니다.
Android 사용자는 Material Design에 익숙하고, iOS 사용자는 Apple의 Human Interface Guidelines에 익숙하기 때문입니다.

플랫폼별 기대#

Android 사용자:
- 화면 하단의 네비게이션 바
- FloatingActionButton
- 카드와 그림자 효과
iOS 사용자:
- 화면 상단의 큰 제목
- 하단 탭 바와 액션 시트
- 블러 효과와 반투명 요소

문제는 다음과 같습니다.

  • 하나의 디자인으로 두 플랫폼을 만족시키기 어렵다.
  • 플랫폼별 코드를 직접 분기하면 유지보수가 복잡해진다.
  • 네이티브 느낌을 주지 못하면 사용자 경험이 저하된다.

해결 방법#

Flutter는 Material과 Cupertino라는 두 가지 디자인 시스템을 제공합니다.
Material은 Android 스타일, Cupertino는 iOS 스타일입니다.
각 시스템은 해당 플랫폼의 디자인 가이드라인을 충실히 구현합니다.

챕터 1: Material Design 이해하기#

Why#

NOTE

Material Design은 Google이 만든 디자인 시스템입니다.
Android뿐 아니라 웹, 데스크톱에서도 널리 사용됩니다.
Flutter는 Material Design을 기본으로 채택하고 있어, 별도 설정 없이 바로 사용할 수 있습니다.

// Material Design이 기본
MaterialApp(
home: Scaffold(...),
)

What#

NOTE

Material Design 33는 Google이 2021년 발표한 최신 디자인 시스템입니다.
Flutter 3.16부터 Material 3가 기본으로 활성화되어 있습니다.
새 프로젝트를 만들면 자동으로 적용됩니다.

How#

TIP

Material Design의 핵심 요소는 다음과 같습니다.

요소설명예시
색상 시스템동적 색상과 테마ColorScheme, ThemeData
타이포그래피일관된 텍스트 스타일TextTheme
컴포넌트미리 정의된 위젯Button, Card, AppBar
음영과 깊이계층 표현elevation 속성

Material 3 활성화 확인

MaterialApp(
theme: ThemeData(
useMaterial3: true, // 기본값 (Flutter 3.16+)
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
),
),
home: MyApp(),
)

기본 Material 앱 구조

MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Material 앱'),
),
body: Center(
child: ElevatedButton(
onPressed: () {},
child: Text('버튼'),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add),
),
),
)

Watch out#

WARNING

Material 2에서 Material 3로 마이그레이션할 때 일부 위젯의 외관이 변경됩니다. 기존 앱의 디자인이 변경될 수 있으므로 확인이 필요합니다.

// Material 2로 유지하려면 (권장하지 않음)
ThemeData(
useMaterial3: false, // 향후 지원 중단 예정
)

결론: Flutter는 Material 3를 기본으로 사용하며, 모던하고 일관된 디자인을 제공합니다.


챕터 2: Material 주요 위젯#

Why#

NOTE

Material Design은 6가지 카테고리로 위젯을 분류합니다.
버튼, 네비게이션, 선택, 컨테이너 등으로 나뉘어 있습니다.
각 카테고리의 대표 위젯을 알면 필요한 위젯을 빠르게 찾을 수 있습니다.

What#

NOTE

Material 위젯은 Actions, Communication, Containment, Navigation, Selection, Text inputs로 분류됩니다.

How#

TIP

Actions (작업) 위젯

사용자 동작을 시작하는 버튼류 위젯입니다.

위젯용도예시
ElevatedButton주요 작업저장, 전송
FilledButton강조 작업확인
OutlinedButton보조 작업취소
TextButton덜 중요한 작업더 보기
FloatingActionButton4화면의 주요 작업새 글 작성
IconButton아이콘 클릭좋아요, 공유
Column(
children: [
ElevatedButton(onPressed: () {}, child: Text('Elevated')),
FilledButton(onPressed: () {}, child: Text('Filled')),
OutlinedButton(onPressed: () {}, child: Text('Outlined')),
TextButton(onPressed: () {}, child: Text('Text')),
],
)

Navigation (네비게이션) 위젯

앱 내 이동을 담당하는 위젯입니다.

위젯용도위치
AppBar화면 제목과 작업상단
NavigationBar주요 목적지 전환하단
NavigationRail태블릿/데스크톱 네비게이션좌측
NavigationDrawer메뉴 목록슬라이드
TabBar탭 전환상단/하단
Scaffold(
appBar: AppBar(title: Text('제목')),
body: content,
bottomNavigationBar: NavigationBar(
destinations: [
NavigationDestination(icon: Icon(Icons.home), label: '홈'),
NavigationDestination(icon: Icon(Icons.search), label: '검색'),
NavigationDestination(icon: Icon(Icons.person), label: '프로필'),
],
selectedIndex: 0,
onDestinationSelected: (index) {},
),
)

Selection (선택) 위젯

사용자가 옵션을 선택하는 폼 컨트롤입니다.

위젯용도선택 방식
Checkbox다중 선택체크
Radio단일 선택라디오
SwitchON/OFF 토글스위치
Slider범위 선택슬라이더
Chip필터링, 선택
DropdownMenu목록 선택드롭다운
Column(
children: [
Checkbox(value: true, onChanged: (v) {}),
Switch(value: false, onChanged: (v) {}),
Slider(value: 0.5, onChanged: (v) {}),
],
)

Containment (컨테이너) 위젯

콘텐츠를 담는 컨테이너 위젯입니다.

위젯용도
Card관련 정보 그룹화
AlertDialog사용자 확인 요청
BottomSheet추가 옵션 표시
ListTile목록 항목
Divider구분선
Card(
child: ListTile(
leading: Icon(Icons.album),
title: Text('제목'),
subtitle: Text('부제목'),
trailing: Icon(Icons.more_vert),
),
)

Watch out#

WARNING

Material 위젯은 Material ancestor가 필요합니다. MaterialApp 없이 Material 위젯을 사용하면 오류가 발생합니다.

// 오류: Material ancestor 없음
runApp(ElevatedButton(...)); // 오류!
// 올바른 사용
runApp(MaterialApp(
home: ElevatedButton(...),
));

결론: Material 위젯은 카테고리별로 정리되어 있어 목적에 맞는 위젯을 쉽게 찾을 수 있습니다.


챕터 3: Cupertino 디자인 이해하기#

Why#

NOTE

iOS 사용자는 Apple의 Human Interface Guidelines에 익숙합니다.
iOS 앱다운 네이티브 경험을 제공하려면 어떻게 해야 할까요?
Cupertino 위젯을 사용하면 됩니다.

Material: 그림자, 물결 효과, 밝은 색상
Cupertino: 반투명, 블러 효과, 미니멀

What#

NOTE

Cupertino는 Flutter에서 iOS/macOS 스타일의 위젯을 제공합니다.
Apple의 Human Interface Guidelines를 따르는 디자인을 구현합니다.
반투명 효과, 블러, 미니멀한 디자인이 특징입니다.

How#

TIP

Cupertino 앱 기본 구조

import 'package:flutter/cupertino.dart';
CupertinoApp(
home: CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('Cupertino 앱'),
),
child: Center(
child: CupertinoButton(
onPressed: () {},
child: Text('버튼'),
),
),
),
)

Material vs Cupertino 비교

기능MaterialCupertino
앱 루트MaterialAppCupertinoApp
페이지 구조ScaffoldCupertinoPageScaffold
앱 바AppBarCupertinoNavigationBar
버튼ElevatedButtonCupertinoButton
스위치SwitchCupertinoSwitch
알림창AlertDialogCupertinoAlertDialog
탭 바BottomNavigationBarCupertinoTabBar
텍스트 필드TextFieldCupertinoTextField

시각적 차이

graph LR subgraph Material A[AppBar] --> B[그림자와 elevation] C[Button] --> D[물결 효과 ripple] E[Switch] --> F[둥근 사각형] end subgraph Cupertino G[NavigationBar] --> H[반투명 블러] I[Button] --> J[하이라이트 효과] K[Switch] --> L[캡슐 모양] end

Watch out#

WARNING

Cupertino 위젯은 CupertinoApp 또는 CupertinoTheme이 필요합니다. Material 앱에서 Cupertino 위젯을 사용하려면 추가 설정이 필요합니다.

// Material 앱에서 Cupertino 위젯 사용
MaterialApp(
home: Scaffold(
body: CupertinoButton( // 일부 위젯은 동작하지만
child: Text('버튼'), // 테마가 적용되지 않을 수 있음
onPressed: () {},
),
),
)

결론: iOS 네이티브 경험이 중요한 앱에서는 Cupertino 위젯을 활용합니다.


챕터 4: Cupertino 주요 위젯#

Why#

NOTE

Cupertino 위젯은 iOS 특유의 UX 패턴을 구현합니다.
피커, 액션 시트, 슬라이딩 세그먼트 등이 있습니다.
이런 컴포넌트는 iOS에서만 볼 수 있는 것들입니다.

What#

NOTE

Cupertino 위젯은 네비게이션, 입력, 선택, 피드백 등의 카테고리로 분류됩니다.

How#

TIP

네비게이션 위젯

위젯용도특징
CupertinoNavigationBar상단 네비게이션자동 뒤로가기
CupertinoSliverNavigationBar큰 제목 지원iOS 11 스타일
CupertinoTabBar하단 탭 바아이콘 + 라벨
CupertinoTabScaffold탭 기반 레이아웃TabBar + 콘텐츠
CupertinoTabScaffold(
tabBar: CupertinoTabBar(
items: [
BottomNavigationBarItem(icon: Icon(CupertinoIcons.home), label: '홈'),
BottomNavigationBarItem(icon: Icon(CupertinoIcons.search), label: '검색'),
BottomNavigationBarItem(icon: Icon(CupertinoIcons.settings), label: '설정'),
],
),
tabBuilder: (context, index) {
return CupertinoPageScaffold(
child: Center(child: Text('탭 $index')),
);
},
)

선택 위젯 (Picker)

iOS의 특징적인 휠 스타일 피커입니다.

위젯용도
CupertinoPicker일반 항목 선택
CupertinoDatePicker날짜/시간 선택
CupertinoTimerPicker타이머 설정
CupertinoSlidingSegmentedControl세그먼트 선택
CupertinoDatePicker(
mode: CupertinoDatePickerMode.date,
onDateTimeChanged: (DateTime newDate) {
print(newDate);
},
)

대화상자 위젯

위젯용도등장 방식
CupertinoAlertDialog확인/취소 선택중앙 팝업
CupertinoActionSheet여러 옵션 선택하단 슬라이드
CupertinoContextMenu컨텍스트 메뉴롱프레스
// 알림창 표시
showCupertinoDialog(
context: context,
builder: (context) => CupertinoAlertDialog(
title: Text('제목'),
content: Text('내용'),
actions: [
CupertinoDialogAction(
child: Text('취소'),
onPressed: () => Navigator.pop(context),
),
CupertinoDialogAction(
isDefaultAction: true,
child: Text('확인'),
onPressed: () => Navigator.pop(context),
),
],
),
);

입력 위젯

위젯용도
CupertinoTextField텍스트 입력
CupertinoSearchTextField검색 입력
CupertinoSwitchON/OFF 토글
CupertinoSlider범위 선택
CupertinoTextField(
placeholder: '이름을 입력하세요',
prefix: Icon(CupertinoIcons.person),
padding: EdgeInsets.all(12),
)

Watch out#

WARNING

Cupertino 아이콘은 별도 패키지인 cupertino_icons가 필요합니다. pubspec.yaml에서 의존성을 확인하세요.

dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2 # 필수

결론: Cupertino 위젯으로 피커, 액션시트 등 iOS 특유의 UX를 구현합니다.


챕터 5: 플랫폼별 위젯 선택 전략#

Why#

NOTE

크로스플랫폼 앱에서 어떤 디자인 시스템을 사용해야 할까요?
모든 플랫폼에서 동일한 디자인을 쓸지, 플랫폼별로 다르게 할지 선택이 필요합니다.
세 가지 전략이 있습니다.

What#

NOTE

세 가지 전략이 있습니다: Material 통일, 플랫폼별 분기, 하이브리드 방식입니다.

How#

TIP

전략 1: Material 통일

모든 플랫폼에서 Material Design을 사용합니다.

// 단순하고 일관된 코드
MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('앱')),
body: MyContent(),
),
)
장점단점
코드 단순화iOS에서 어색할 수 있음
일관된 디자인플랫폼 기대와 다름
유지보수 용이네이티브 경험 부족

전략 2: 플랫폼별 분기

Platform에 따라 다른 위젯을 사용합니다.

import 'dart:io';
Widget build(BuildContext context) {
if (Platform.isIOS) {
return CupertinoApp(
home: CupertinoPageScaffold(...),
);
}
return MaterialApp(
home: Scaffold(...),
);
}
장점단점
네이티브 경험코드 복잡도 증가
플랫폼 기대 충족유지보수 부담
최적화된 UX두 배의 위젯 코드

전략 3: 하이브리드 방식 (권장)

기본은 Material을 사용하고, 필요한 부분만 플랫폼별로 분기합니다.

MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('앱')),
body: Column(
children: [
// 공통 콘텐츠
Text('콘텐츠'),
// 플랫폼별 위젯
Platform.isIOS
? CupertinoButton(onPressed: () {}, child: Text('버튼'))
: ElevatedButton(onPressed: () {}, child: Text('버튼')),
],
),
),
)

플랫폼 적응형 위젯 사용

일부 위젯은 자동으로 플랫폼에 적응합니다.

// 자동 적응 예시
showDialog(...) // Material AlertDialog
showCupertinoDialog(...) // Cupertino AlertDialog
// 적응형 위젯
Switch.adaptive(...) // 플랫폼별 자동 적응
Slider.adaptive(...)

Watch out#

WARNING

Platform.isIOS는 웹에서 사용할 수 없습니다. 웹을 지원하려면 Theme.of(context).platform을 사용하세요.

// 웹에서도 동작하는 방식
final isIOS = Theme.of(context).platform == TargetPlatform.iOS;

결론: 대부분의 앱은 Material을 기본으로 하고, 필요한 곳에서만 플랫폼별 분기를 사용합니다.


한계#

디자인 시스템 선택에는 트레이드오프가 있습니다.
어떤 방식이든 장단점이 있습니다.

  • 코드 복잡도: 플랫폼별 분기가 많아지면 유지보수가 어려워집니다.
  • 일관성 vs 네이티브: 모든 플랫폼에서 동일한 경험과 플랫폼별 최적화 사이의 균형이 필요합니다.
  • 학습 비용: 두 디자인 시스템을 모두 익혀야 합니다.

Footnotes#

  1. Material Design(머티리얼 디자인): Google이 만든 디자인 시스템으로 그림자, 깊이, 물결 효과 등이 특징이다.

  2. Cupertino(쿠퍼티노): Apple의 Human Interface Guidelines를 따르는 iOS/macOS 스타일 디자인이다. Apple 본사가 있는 도시 이름에서 유래했다.

  3. Material 3(머티리얼 3): 2021년 발표된 Material Design의 최신 버전으로 동적 색상, 개선된 접근성이 특징이다.

  4. FloatingActionButton(플로팅 액션 버튼): 화면 위에 떠 있는 원형 버튼으로 앱의 주요 작업을 나타낸다.

공유

이 글이 도움이 되었다면 다른 사람과 공유해주세요!

Flutter 튜토리얼 5편: Material과 Cupertino 위젯
https://moodturnpost.net/posts/flutter/flutter-design-systems/
작성자
Moodturn
게시일
2026-01-08
Moodturn

목차