티스토리 뷰
Flutter로 애플리케이션을 개발할 때, 일관된 디자인을 유지하기 위해 테마(Theme)를 사용하는 것이 중요합니다. 이 블로그 포스트에서는 Flutter에서 테마를 정의하고 사용하는 방법, 테마를 적용하고 확장하는 방법, 그리고 특정 부분에서 테마를 덮어쓰는 방법을 살펴봅니다. 이를 통해 앱의 색상과 글꼴 스타일을 효율적으로 공유하고 관리할 수 있는 방법을 익힐 수 있습니다.
Flutter에서 테마란 무엇인가?
테마는 Flutter 애플리케이션 전반에 걸쳐 색상, 글꼴 스타일, 버튼 스타일 등의 디자인 요소를 통일된 방식으로 적용하는 시스템입니다. Flutter는 기본적으로 Material 3 테마를 지원하며, 이를 통해 사용자 인터페이스(UI) 전반에 일관된 스타일을 부여할 수 있습니다.
테마를 정의하고 적용하는 방법
1. 앱 전체에 테마 설정하기
Flutter에서는 MaterialApp
생성자에서 theme
속성을 사용하여 애플리케이션의 기본 테마를 설정할 수 있습니다. 이 속성은 ThemeData
인스턴스를 받으며, 여기서 색상, 글꼴 스타일, 밝기 등을 정의할 수 있습니다. 예를 들어, 다음 코드는 앱 전체에 Material 3 테마를 적용하는 방법을 보여줍니다.
MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(seedColor: Colors.purple),
textTheme: TextTheme(
displayLarge: TextStyle(fontSize: 72, fontWeight: FontWeight.bold),
titleLarge: GoogleFonts.oswald(fontSize: 30, fontStyle: FontStyle.italic),
bodyMedium: GoogleFonts.merriweather(),
),
),
home: MyHomePage(title: 'Flutter Home'),
);
위 코드에서는 ColorScheme
을 사용해 기본 색상 팔레트를 설정하고, TextTheme
을 통해 텍스트 스타일을 정의했습니다. 이로 인해 앱 전반에 걸쳐 일관된 색상과 글꼴이 적용됩니다.
2. 테마를 위젯에 적용하기
위젯의 스타일 속성에 테마를 적용하려면 Theme.of(context)
메서드를 사용합니다. 이 메서드는 위젯 트리에서 가장 가까운 테마를 찾아 그 스타일을 적용합니다. 예를 들어, Container
위젯에 테마 색상을 적용하는 코드는 다음과 같습니다.
Container(
padding: EdgeInsets.all(12),
color: Theme.of(context).colorScheme.primary,
child: Text(
'테마 색상이 적용된 텍스트',
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.onPrimary,
),
),
);
3. 특정 부분에서 테마 덮어쓰기
애플리케이션 전체에 적용된 테마를 특정 부분에서 덮어쓰고 싶다면, 해당 부분을 Theme
위젯으로 감싸고 ThemeData
를 설정할 수 있습니다. 예를 들어, 특정 버튼에 다른 색상 테마를 적용하는 코드는 다음과 같습니다.
Theme(
data: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.pink),
),
child: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add),
),
);
테마 확장하기
전체 테마를 덮어쓰는 대신, 부모 테마를 확장해 일부 속성만 변경할 수도 있습니다. 이를 위해 copyWith()
메서드를 사용합니다. 이 방법은 기존 테마 스타일을 유지하면서 특정 속성만 수정할 때 유용합니다.
Theme(
data: Theme.of(context).copyWith(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.pink),
),
child: FloatingActionButton(
onPressed: null,
child: Icon(Icons.add),
),
);
테마를 사용한 디자인 최적화 팁
- 일관된 디자인 유지: 테마를 사용하면 앱 전반에 걸쳐 일관된 디자인을 유지할 수 있습니다. 이는 사용자 경험(UX)을 향상시키고, 코드의 유지 보수성을 높여줍니다.
- 색상 팔레트 최적화:
ColorScheme
을 사용해 앱의 색상 팔레트를 중앙에서 관리하면 디자인 변경 시 효율적으로 대응할 수 있습니다. - 글꼴 스타일 관리:
TextTheme
을 통해 다양한 텍스트 스타일을 미리 정의해 두면, 텍스트의 크기나 두께 등을 일관되게 적용할 수 있습니다.
Flutter 테마 적용 시 주의사항
- 기본 테마 설정: Flutter는 테마를 지정하지 않으면 기본 Material 테마를 사용합니다. 따라서 테마를 명시적으로 설정하는 것이 좋습니다.
- 테마 중첩 관리: 여러 테마가 중첩될 경우, 가장 가까운 상위 테마가 적용되므로 테마의 적용 범위를 명확히 관리해야 합니다.
결론
Flutter에서 테마를 사용하면 애플리케이션의 색상과 글꼴 스타일을 일관되게 적용할 수 있어 디자인 품질을 높일 수 있습니다. 또한 테마를 확장하거나 덮어쓰는 방법을 사용해 세부적인 스타일 변경도 유연하게 처리할 수 있습니다. 이러한 테마 시스템은 앱의 유지 보수성과 사용자 경험을 모두 향상시키는 강력한 도구입니다.
import 'package:flutter/material.dart';
// Include the Google Fonts package to provide more text format options
// https://pub.dev/packages/google_fonts
import 'package:google_fonts/google_fonts.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
const appName = 'Custom Themes';
return MaterialApp(
title: appName,
theme: ThemeData(
useMaterial3: true,
// Define the default brightness and colors.
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.purple,
// TRY THIS: Change to "Brightness.light"
// and see that all colors change
// to better contrast a light background.
brightness: Brightness.dark,
),
// Define the default `TextTheme`. Use this to specify the default
// text styling for headlines, titles, bodies of text, and more.
textTheme: TextTheme(
displayLarge: const TextStyle(
fontSize: 72,
fontWeight: FontWeight.bold,
),
// TRY THIS: Change one of the GoogleFonts
// to "lato", "poppins", or "lora".
// The title uses "titleLarge"
// and the middle text uses "bodyMedium".
titleLarge: GoogleFonts.oswald(
fontSize: 30,
fontStyle: FontStyle.italic,
),
bodyMedium: GoogleFonts.merriweather(),
displaySmall: GoogleFonts.pacifico(),
),
),
home: const MyHomePage(
title: appName,
),
);
}
}
class MyHomePage extends StatelessWidget {
final String title;
const MyHomePage({super.key, required this.title});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title,
style: Theme.of(context).textTheme.titleLarge!.copyWith(
color: Theme.of(context).colorScheme.onSecondary,
)),
backgroundColor: Theme.of(context).colorScheme.secondary,
),
body: Center(
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 12,
),
color: Theme.of(context).colorScheme.primary,
child: Text(
'Text with a background color',
// TRY THIS: Change the Text value
// or change the Theme.of(context).textTheme
// to "displayLarge" or "displaySmall".
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.onPrimary,
),
),
),
),
floatingActionButton: Theme(
data: Theme.of(context).copyWith(
// TRY THIS: Change the seedColor to "Colors.red" or
// "Colors.blue".
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.pink,
brightness: Brightness.dark,
),
),
child: FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.add),
),
),
);
}
}
'Flutter Cookbook' 카테고리의 다른 글
Flutter에서 다운로드 버튼 구현하기: 단계별 가이드 (1) | 2024.10.18 |
---|---|
탭(Tab) 만들기: 쉽고 효율적인 사용자 인터페이스 구현 (0) | 2024.10.17 |
커스텀 폰트 사용법 완벽 가이드 (2) | 2024.10.15 |
화면 회전에 따른 UI 변경: OrientationBuilder와 MediaQuery 활용법 (1) | 2024.10.14 |
패키지 폰트 사용 방법: 폰트 재사용을 위한 최적화된 접근 (5) | 2024.10.13 |