Material 3 ํ ๋ง์ ๋คํฌ ๋ชจ๋
์ง๋ ๊ธ๊น์ง ํ๋ฉด์ ๋ง๋ค๊ณ ์ ๋ ฅ์ ๋ฐ๋ ๋ฒ์ ๋ดค์ผ๋, ์ด๋ฒ์ ์ฑ ์ ์ฒด์ ์๊ณผ ๊ธ๊ผด์ ํ ๊ณณ์์ ์ ํ๋ ํ ๋ง๋ค. ํ๋ฉด๋ง๋ค ์์ ์ง์ ์ง์ ํด์ ์นด๋๋ฅผ ํ๋ ๋ง๋ค์ด๋ณด์.
Container(
padding: const EdgeInsets.all(16),
color: Colors.white, // ์นด๋ ๋ฐฐ๊ฒฝ์ ํฐ์์ผ๋ก ์ง์ ์ง์
child: const Text('์๋
ํ์ธ์'),
)๋ฐ์ ๋ชจ๋์์๋ ๋ฌธ์ ์์ด ๋ณด์ธ๋ค. ๊ทธ๋ฐ๋ฐ ํฐ์ ๋คํฌ ๋ชจ๋๋ก ๋ฐ๊พธ๊ณ ์ฑ์ ์ผ๋ฉด(์ฑ์ darkTheme์ ์ค์ ํด ๋ ์ํ๋ผ๊ณ ํ์) ์นด๋๊ฐ ํ์ ํ ์์ ํ์ ๊ธ์๊ฐ ๋๋ค. Text๋ ํ
๋ง๋ฅผ ๋ฐ๋ผ ๊ธ์์์ด ํฐ์์ผ๋ก ๋ฐ๋๋๋ฐ, ๋ฐฐ๊ฒฝ์ ๋ด๊ฐ Colors.white๋ก ๋ฐ์๋๊ธฐ ๋๋ฌธ์ ์ ๋ฐ๋๋ค. ๊ธ์๊ฐ ๋ณด์ด์ง ์๋๋ค.
์์ธ: ์์ ์์ ฏ๋ง๋ค ์ง์ ์ง์ ํ๋ฉด ํ ๋ง๊ฐ ๋ฐ๊ฟ์ค ์ ์๋ค
์ง๋ ๊ธ๋ค์์ MaterialApp์ด ํ
๋ง๋ฅผ ์๋๋ก ๋ด๋ ค์ค๋ค๊ณ ํ๋ค. ์์ ฏ์ด Theme์์ ์์ ๊บผ๋ด ์ฐ๋ฉด ํ
๋ง๊ฐ ๋ฐ๋ ๋ ๊ฐ์ด ๋ฐ๋๊ณ , Colors.white์ฒ๋ผ ๊ฐ์ ์ง์ ์ฐ๋ฉด ํ
๋ง์ ์๊ด์์ด ๊ทธ ์์ ๊ณ ์ ๋๋ค. ์ฑ ์ ์ฒด ์์ ๋ฐ๊พธ๊ฑฐ๋ ๋คํฌ ๋ชจ๋๋ฅผ ์ง์ํ๋ ค๋ฉด ์์ ํ
๋ง์์ ๊บผ๋ด ์ฐ๋ ์ต๊ด์ด ํ์ํ๋ค.
ํด๊ฒฐ 1: ThemeData๋ก ์ฑ ์ ์ฒด ์ ์ ํ๊ธฐ
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal),
),
home: const HomePage(),
);
}
}ColorScheme.fromSeed๋ ๊ธฐ์ค ์ ํ๋(seed)๋ก ์ด์ธ๋ฆฌ๋ ์ ๋ฌถ์์ ์๋์ผ๋ก ๋ง๋ค์ด์ค๋ค. Colors.teal ํ๋๋ง ์ ํ๋ฉด ๋ฒํผ ์, ๋ฐฐ๊ฒฝ์, ๊ธ์์ ๋ฑ ์์ญ ๊ฐ๊ฐ ์์์ ์ ํด์ง๋ค. Material 3๋ ์ด "์ ๋ฌถ์(ColorScheme)"์ด ํต์ฌ์ด๋ค. ์ฒ์ ๋ง๋ Flutter ํ๋ก์ ํธ์ Colors.deepPurple ๋ณด๋ผ์ ์ฑ๋ฐ๊ฐ ์ด ๋ฐฉ์์ด๋ค.
Material 3๋ Flutter 3.16๋ถํฐ ๊ธฐ๋ณธ๊ฐ์ด๋ผ์, ์์ฆ ํ๋ก์ ํธ๋ ๋ฐ๋ก ์ผ์ง ์์๋ ๋๋ค.
ํด๊ฒฐ 2: ์์ ฏ์์๋ ํ ๋ง์์ ๊บผ๋ด ์ฐ๊ธฐ
Container(
padding: const EdgeInsets.all(16),
color: Theme.of(context).colorScheme.surfaceContainer, // ํ
๋ง์์ ๊บผ๋
child: Text(
'์๋
ํ์ธ์',
style: TextStyle(color: Theme.of(context).colorScheme.onSurface),
),
)Theme.of(context)๋ StatelessWidget ๊ธ์์ ๋ณธ ๋๋ก ํธ๋ฆฌ์์ ๋ด ์์น๋ก๋ถํฐ ์๋ก ์ฌ๋ผ๊ฐ ๊ฐ์ฅ ๊ฐ๊น์ด ํ
๋ง๋ฅผ ์ฐพ์์ค๋ ์ฝ๋๋ค. ์ด์ ๋ฐ์ ๋ชจ๋์์๋ ๋ฐ์ ๋ฐฐ๊ฒฝ๊ณผ ์ด๋์ด ๊ธ์, ๋คํฌ ๋ชจ๋์์๋ ๋ฐ๋๋ก ์์์ ๋ฐ๋๋ค.
์ ์ด๋ฆ์ ๊ท์น: ์ง์ผ๋ก ๋ค๋๋ค
ColorScheme์ ์์ ๋ฐฐ๊ฒฝ์ฉ ์๊ณผ ๊ทธ ์์ ์ฌ๋ผ๊ฐ๋ ์์ด ์ง์ด๋ค.
primary/onPrimary: ์ฃผ์ ๋ฒํผ, ๊ฐ์กฐsurface/onSurface: ํ๋ฉดยท์นด๋ ๋ฐํ๊ณผ ๊ทธ ์ ๊ธ์secondary/onSecondary: ๋ณด์กฐ ๊ฐ์กฐerror/onError: ์๋ฌ ํ์
on์ "์ด ์ ์์ ์ฌ๋ผ๊ฐ๋ ์"์ด๋ผ๋ ๋ป์ด๋ค. primary ์์ ๊ธ์๋ฅผ ์ธ ๋ onPrimary๋ฅผ ์ฐ๋ฉด ๋ฐฐ๊ฒฝ์ด ๋ฐ๋ ์ด๋ก๋ ์ฝ์ ์ ์๋ ์์ด ๋ณด์ฅ๋๋ค. ์ง์ ์ง์ผ์ ์ฐ๋ ๊ฒ ํ
๋ง๋ฅผ ์ฐ๋ ์๋ น์ด๋ค.
๋คํฌ ๋ชจ๋: darkTheme๊ณผ themeMode
MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal),
),
darkTheme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.teal,
brightness: Brightness.dark, // ๊ฐ์ seed๋ก ์ด๋์ด ๋ฒ์
),
),
themeMode: ThemeMode.system, // ๊ธฐ๊ธฐ ์ค์ ์ ๋ฐ๋ผ๊ฐ
home: const HomePage(),
)theme: ๋ฐ์ ๋ชจ๋ ํ ๋งdarkTheme: ๋คํฌ ๋ชจ๋ ํ ๋ง. ๊ฐ์seedColor์brightness: Brightness.dark๋ง ์ฃผ๋ฉด ์ด์ธ๋ฆฌ๋ ์ด๋์ด ์์ด ๋ง๋ค์ด์ง๋คthemeMode: ์ด๋ ์ชฝ์ ์ธ์ง ์ ํ๋ค
themeMode์ ๋ฃ์ ์ ์๋ ๊ฐ์ ์ธ ๊ฐ์ง๋ค.
ThemeMode.system: ๊ธฐ๊ธฐ์ ๋คํฌ ๋ชจ๋ ์ค์ ์ ๋ฐ๋ฅธ๋ค (๊ธฐ๋ณธ๊ฐ)ThemeMode.light: ํญ์ ๋ฐ๊ฒThemeMode.dark: ํญ์ ์ด๋ก๊ฒ
darkTheme์ ์ ์ ์ผ๋ฉด ๊ธฐ๊ธฐ๊ฐ ๋คํฌ ๋ชจ๋์ฌ๋ ๋ฐ์ ํ
๋ง๊ฐ ๊ทธ๋๋ก ์ฐ์ด๋, ๋คํฌ ๋ชจ๋๋ฅผ ์ง์ํ๋ ค๋ฉด ๋ ๋ค ์ ์ด์ผ ํ๋ค.
์ฑ ์์์ ๋คํฌ ๋ชจ๋ ์ค์์น ๋ง๋ค๊ธฐ
์ค์ ํ๋ฉด์์ ์ฌ์ฉ์๊ฐ ์ง์ ๋ฐ๊ฒยท์ด๋ก๊ฒ๋ฅผ ๊ณ ๋ฅด๊ฒ ํ๋ ค๋ฉด themeMode๋ฅผ ์ํ๋ก ๋ค๊ณ ์๋ค๊ฐ ๋ฐ๊พธ๋ฉด ๋๋ค. StatefulWidget๊ณผ setState๊ฐ ๊ทธ๋๋ก ์ฐ์ธ๋ค.
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
ThemeMode themeMode = ThemeMode.system;
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal)),
darkTheme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.teal,
brightness: Brightness.dark,
),
),
themeMode: themeMode,
home: Scaffold(
body: Center(
child: Switch(
value: themeMode == ThemeMode.dark,
onChanged: (isDark) {
setState(() {
themeMode = isDark ? ThemeMode.dark : ThemeMode.light;
});
},
),
),
),
);
}
}์ค์์น๋ฅผ ์ผ๋ฉด setState๋ก themeMode๊ฐ ๋ฐ๋๊ณ , MaterialApp์ด ๋ค์ ๊ทธ๋ ค์ง๋ฉด์ ์ฑ ์ ์ฒด๊ฐ ์ด๋์์ง๋ค. ์ด ๊ฐ์ ์ฑ์ ๊ป๋ค ์ผ๋ ์ ์งํ๋ ค๋ฉด ๋ก์ปฌ ์ ์ฅ์๊ฐ ํ์ํ๋ฐ, 4๋จ๊ณ์์ ๋ค๋ฃฌ๋ค.
๊ธ๊ผด ํฌ๊ธฐ๋ textTheme์ผ๋ก
๊ธ์๋ TextStyle(fontSize: 24)์ฒ๋ผ ์ซ์๋ฅผ ์ง์ ์ ์ง ๋ง๊ณ ํ
๋ง์ ์ด๋ฆ ๋ถ์ ์คํ์ผ์ ์ด๋ค.
Text('์ ๋ชฉ', style: Theme.of(context).textTheme.headlineMedium)
Text('๋ณธ๋ฌธ', style: Theme.of(context).textTheme.bodyLarge)headlineMedium, titleLarge, bodyMedium, labelSmall์ฒ๋ผ ์ฉ๋๋ณ๋ก ํฌ๊ธฐ์ ๊ตต๊ธฐ๊ฐ ์ ํด์ ธ ์๋ค. ์ฑ ์ ์ฒด ๊ธ๊ผด์ ๋ฐ๊พธ๊ณ ์ถ์ ๋ ํ ๊ณณ๋ง ๊ณ ์น๋ฉด ๋๋ค.
ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal),
textTheme: const TextTheme(
bodyLarge: TextStyle(fontSize: 18),
),
)์ฒ์ ๋ง๋ Flutter ์ฑ์ Theme.of(context).textTheme.headlineMedium์ด ์ซ์ ํ์์ ์ฐ์ธ ๊ฒ ์ด ๋ฐฉ์์ด๋ค.
ํน์ ์์ ฏ๋ง ์ผ๊ด๋ก ๊พธ๋ฏธ๊ธฐ
๋ฒํผ ๋ชจ์์ ์ฑ ์ ์ฒด์์ ๋๊ฐ์ด ๋ง์ถ๊ณ ์ถ๋ค๋ฉด ์์ ฏ๋ณ ํ ๋ง๋ฅผ ์ด๋ค.
ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
),
)์ด๋ฌ๋ฉด ์ฑ ์์ ๋ชจ๋ ElevatedButton์ด ๋ฅ๊ทผ ๋ชจ์๋ฆฌ๋ฅผ ๊ฐ๋๋ค. ํ๋ฉด๋ง๋ค ๋ฒํผ์ ๋ฐ๋ก ๊พธ๋ฏธ์ง ์์๋ ๋๋ค.
Compose, SwiftUI์ ๋น๊ตํ๋ฉด
// Compose
MaterialTheme(
colorScheme = if (isSystemInDarkTheme()) darkColorScheme() else lightColorScheme()
) {
Text("์๋
", color = MaterialTheme.colorScheme.onSurface)
}// SwiftUI
Text("์๋
")
.foregroundStyle(.primary) // ๋คํฌ ๋ชจ๋์์ ์๋์ผ๋ก ๋ฐ๋๋ ์๋ฏธ ์
.preferredColorScheme(.dark)ํญ๋ชฉ๋ณ๋ก ๋๋ํ ๋์ผ๋ฉด ์ด๋ ๋ค.
- ํ
๋ง ์ ์: Flutter
ThemeData/ ComposeMaterialTheme/ SwiftUI ์์ ์นดํ๋ก๊ทธ์ ์ ์ธํธ - ์ ๋ฌถ์: Flutter
ColorScheme.fromSeed/ ComposelightColorScheme(),darkColorScheme()/ SwiftUI ์์คํ ์๋ฏธ ์(.primary๋ฑ) - ์์ ฏ์์ ๊บผ๋ด๊ธฐ: Flutter
Theme.of(context).colorScheme/ ComposeMaterialTheme.colorScheme/ SwiftUIColor.primary๋ฑ - ๋คํฌ ๋ชจ๋ ์ ํ: Flutter
themeMode/ ComposeisSystemInDarkTheme()/ SwiftUIpreferredColorScheme - ๊ธ๊ผด ์คํ์ผ: Flutter
textTheme/ ComposeMaterialTheme.typography/ SwiftUIFont์คํ์ผ
Compose์ MaterialTheme๊ณผ ๊ตฌ์กฐ๊ฐ ๊ฑฐ์ ๊ฐ๋ค. Flutter๋ Theme.of(context)๋ก ๊บผ๋ด๊ณ Compose๋ MaterialTheme.colorScheme์ผ๋ก ๊บผ๋ธ๋ค๋ ์ ์ด ๋ค๋ฅด๋ค. SwiftUI๋ Material ๊ฐ๋
์ด ์์ด์ ์์คํ
์ด ์ ํด๋ ์๋ฏธ ์์ ์ฐ๋ ์ชฝ์ด๋ค.
์ ๋ฆฌ
- ์์
Colors.white์ฒ๋ผ ์์ ฏ๋ง๋ค ์ง์ ์ง์ ํ๋ฉด ํ ๋ง๊ฐ ๋ฐ๊ฟ์ฃผ์ง ๋ชปํด์, ๋คํฌ ๋ชจ๋์์ ๋ฐฐ๊ฒฝ๊ณผ ๊ธ์๊ฐ ์ ๋ณด์ด๋ ์ผ์ด ์๊ธด๋ค ThemeData์ColorScheme.fromSeed(seedColor: ...)๋ก ๊ธฐ์ค ์ ํ๋์์ ์ฑ ์ ์ฒด ์ ๋ฌถ์์ ๋ง๋ค๊ณ , ์์ ฏ์์๋Theme.of(context).colorScheme์์ ๋ฐฐ๊ฒฝ๊ณผon์ง ์์ ๊บผ๋ด ์ด๋ค- ๋คํฌ ๋ชจ๋๋
theme์darkTheme์ ๋ ๋ค ์ ๊ณ ,themeMode๋ก ๊ธฐ๊ธฐ ์ค์ ์ ๋ฐ๋ฅผ์ง ๊ณ ์ ํ ์ง ์ ํ๋ค - ๊ธ๊ผด์
Theme.of(context).textTheme์ ์ด๋ฆ ๋ถ์ ์คํ์ผ์ ์ฐ๊ณ , ๋ฒํผ ๊ฐ์ ์์ ฏ ๊ณตํต ๋ชจ์์ ์์ ฏ๋ณ ํ ๋ง๋ก ํ ๋ฒ์ ์ ํ๋ค
๋ค์ ๊ธ์์๋ ํ๋ฉด ํฌ๊ธฐ์ ๋ฐ๋ผ ๋ ์ด์์์ ๋ฐ๊พธ๋ MediaQuery์ LayoutBuilder๋ฅผ ๋ค๋ค๋ณด๊ฒ ๋ค.
