Theme과 다크모드 — ThemeData로 앱 전체 스타일 관리
Theme과 다크모드 — ThemeData로 앱 전체 스타일 관리
앱의 색상, 폰트, 버튼 스타일 등을 일관되게 관리하려면 Theme을 활용해야 합니다. 특히 다크모드 지원은 이제 거의 필수 기능이 되었습니다.
ThemeData 기본 설정
MaterialApp(
theme: ThemeData(
// Material 3 활성화
useMaterial3: true,
// 시드 컬러로 전체 색상 자동 생성
colorSchemeSeed: Colors.blue,
// 밝기
brightness: Brightness.light,
),
darkTheme: ThemeData(
useMaterial3: true,
colorSchemeSeed: Colors.blue,
brightness: Brightness.dark,
),
// 시스템 설정에 따라 자동 전환
themeMode: ThemeMode.system,
home: const HomeScreen(),
)
ColorScheme 직접 정의
ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF6750A4),
brightness: Brightness.light,
),
)
// 또는 완전 커스텀
ThemeData(
colorScheme: const ColorScheme(
brightness: Brightness.light,
primary: Color(0xFF1976D2),
onPrimary: Colors.white,
secondary: Color(0xFF03DAC6),
onSecondary: Colors.black,
error: Color(0xFFB00020),
onError: Colors.white,
surface: Colors.white,
onSurface: Colors.black,
),
)
Theme에서 색상 사용하기
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Container(
color: colorScheme.surface,
child: Text(
'테마 색상 사용',
style: TextStyle(color: colorScheme.onSurface),
),
);
}
ColorScheme의 주요 색상
| 속성 | 용도 |
|---|---|
primary | 주요 컴포넌트 (버튼, FAB 등) |
onPrimary | primary 위의 텍스트/아이콘 |
secondary | 보조 강조 |
surface | 카드, 시트 등 표면 |
error | 에러 상태 |
outline | 테두리 |
위젯별 테마 커스터마이징
ThemeData(
useMaterial3: true,
colorSchemeSeed: Colors.blue,
// AppBar 테마
appBarTheme: const AppBarTheme(
centerTitle: true,
elevation: 0,
scrolledUnderElevation: 1,
),
// 카드 테마
cardTheme: CardTheme(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
// 버튼 테마
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
// 입력 필드 테마
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
filled: true,
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 12,
),
),
// 텍스트 테마
textTheme: const TextTheme(
displayLarge: TextStyle(fontWeight: FontWeight.bold),
titleLarge: TextStyle(fontWeight: FontWeight.w600),
),
)
다크모드 구현
시스템 설정 자동 감지
MaterialApp(
theme: _lightTheme(),
darkTheme: _darkTheme(),
themeMode: ThemeMode.system, // 시스템 설정 따름
)
ThemeData _lightTheme() {
return ThemeData(
useMaterial3: true,
colorSchemeSeed: Colors.blue,
brightness: Brightness.light,
);
}
ThemeData _darkTheme() {
return ThemeData(
useMaterial3: true,
colorSchemeSeed: Colors.blue,
brightness: Brightness.dark,
);
}
수동 전환 구현
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
ThemeMode _themeMode = ThemeMode.system;
void _toggleTheme() {
setState(() {
_themeMode = _themeMode == ThemeMode.light
? ThemeMode.dark
: ThemeMode.light;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: _lightTheme(),
darkTheme: _darkTheme(),
themeMode: _themeMode,
home: HomeScreen(onToggleTheme: _toggleTheme),
);
}
}
// 토글 버튼
IconButton(
icon: Icon(
Theme.of(context).brightness == Brightness.dark
? Icons.light_mode
: Icons.dark_mode,
),
onPressed: widget.onToggleTheme,
)
Theme 부분 오버라이드
특정 위젯 트리에만 다른 테마를 적용할 수 있습니다.
Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
primary: Colors.red,
),
),
child: ElevatedButton(
onPressed: () {},
child: const Text('빨간 버튼'), // 이 버튼만 빨간색
),
)
현재 테마 정보 확인
@override
Widget build(BuildContext context) {
// 현재 밝기
final isDark = Theme.of(context).brightness == Brightness.dark;
// 시스템 밝기 직접 확인
final platformBrightness = MediaQuery.platformBrightnessOf(context);
return Container(
color: isDark ? Colors.grey.shade900 : Colors.white,
child: Text(isDark ? '다크 모드' : '라이트 모드'),
);
}
테마 관리 패턴
// 테마 상수를 별도 파일로 분리
// lib/theme/app_theme.dart
abstract class AppTheme {
static ThemeData light() {
return ThemeData(
useMaterial3: true,
colorSchemeSeed: _seedColor,
brightness: Brightness.light,
appBarTheme: _appBarTheme,
cardTheme: _cardTheme,
);
}
static ThemeData dark() {
return ThemeData(
useMaterial3: true,
colorSchemeSeed: _seedColor,
brightness: Brightness.dark,
appBarTheme: _appBarTheme,
cardTheme: _cardTheme,
);
}
static const _seedColor = Color(0xFF6750A4);
static const _appBarTheme = AppBarTheme(
centerTitle: true,
elevation: 0,
);
static final _cardTheme = CardTheme(
elevation: 1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
);
}
// 사용
MaterialApp(
theme: AppTheme.light(),
darkTheme: AppTheme.dark(),
themeMode: ThemeMode.system,
)
정리
ThemeData로 앱 전체의 스타일을 한 곳에서 관리합니다- Material 3에서는
colorSchemeSeed로 시드 컬러만 지정하면 전체 색상 팔레트가 자동 생성됩니다 theme+darkTheme+themeMode로 다크모드를 간편하게 구현할 수 있습니다Theme.of(context)로 현재 테마 정보에 접근합니다- 테마 설정은 별도 파일로 분리하면 유지보수가 편합니다
- 하드코딩된 색상 대신
colorScheme의 속성을 사용하는 습관을 들이세요
댓글 로딩 중...