📌 Day 7: Dart & Flutter 기초부터 실전까지! Flutter 테마 설정 (ColorScheme, Typography, 다크 모

2025. 2. 25. 16:02같이 공부합시다 - Flutter/Dart & Flutter 기초부터 실전까지

728x90
반응형

 
 
 
 

📋 개요

🔸 Flutter 앱 개발 시, 색상과 글꼴을 일일이 지정하면 유지보수가 어려움
🔸 ThemeData와 ColorScheme을 활용하면 앱 전체에서 일관된 디자인을 쉽게 적용 가능.
🔸 Flutter 테마 시스템 활용 방법 (ColorScheme, Typography, 다크 모드)
 
 
 

📝 주제

🔸 ColorScheme을 사용한 색상 관리
🔸 Typography를 활용한 텍스트 스타일링
🔸 Material Theme을 이용한 앱 테마 설정
🔸 다크 모드 지원 및 커스텀 테마 적용
 
 
 
 
 


1️⃣ Flutter 테마(Theme) 시스템 이해

📌 Flutter의 테마(Theme)는 앱의 일관된 디자인을 유지하는 핵심 요소
📌 Flutter 테마 시스템의 주요 장점
 
1. 일관된 디자인 유지
→ 모든 화면에서 동일한 스타일 적용 가능
 
🎨 2. 색상 및 글꼴 통합 관리
→ ColorScheme, Typography 설정 활용
 
🌙 3. 다크 모드 지원
→ ThemeMode.system을 사용해 자동 변경 가능
 
🛠️ 4. UI 유지보수 및 코드 재사용성 증가
→ 변경 사항을 한 곳에서 관리
 
 
📌 예제 코드 (기본 테마 설정)

MaterialApp(
  theme: ThemeData(
    colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
    textTheme: TextTheme(bodyLarge: TextStyle(fontSize: 18)),
  ),
  darkTheme: ThemeData.dark(), // 다크 모드 지원
  themeMode: ThemeMode.system, // 시스템 설정에 따라 자동 변경
)

 
✅ 위 코드의 핵심 포인트
1️⃣ ColorScheme.fromSeed(seedColor: Colors.blue) → 앱의 색상을 Blue 계열로 자동 적용
2️⃣ textTheme → 기본 글꼴 스타일 적용 (bodyLarge → 기본 텍스트 크기 18px)
3️⃣ darkTheme: ThemeData.dark() → 다크 모드 자동 지원
4️⃣ themeMode: ThemeMode.system → 시스템 설정에 따라 라이트/다크 모드 자동 변경
 
💡 테마를 설정하면 앱 전체에 적용 가능하며, 유지보수가 쉬워짐!
 
 
 
 
 


2️⃣ ColorScheme (색상 테마) 적용

 
📌 ColorScheme을 활용하여 앱의 주요 색상을 정의하고, ThemeData에 적용

 

📌 기본 ColorScheme 설정

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter 테마 설정',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blue,
          brightness: Brightness.light,
          secondary: Colors.orange,
          surface: Colors.white,
          onPrimary: Colors.white,
        ),
      ),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blue,
          brightness: Brightness.dark,
          secondary: Colors.deepOrange,
          surface: Colors.black,
          onPrimary: Colors.white,
        ),
      ),
      themeMode: ThemeMode.system,
      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("ColorScheme 적용"),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {},
          child: const Text("버튼"),
        ),
      ),
    );
  }
}

 
🔸 Material 3 지원을 위한 ColorScheme.fromSeed() 적용
🔸 라이트 & 다크 모드를 함께 설정하여 다양한 환경에서의 적용 가능성 보강
🔸 themeMode: ThemeMode.system을 설정하여 자동 감지 기능 추가
 
 
 
 
 


3️⃣ Typography (글꼴 스타일) 설정

 
📌 ThemeData.textTheme을 활용하여 앱 전체의 글꼴 스타일을 설정
 
📌 기본 Typography 설정

ThemeData(
	textTheme: const TextTheme(bodyLarge: TextStyle(fontSize: 18)), // 기본 텍스트 스타일
)

 
📌  글꼴(Font Family) 적용 예제

ThemeData(
  fontFamily: 'Roboto',
  textTheme: TextTheme(
    bodyLarge: TextStyle(fontSize: 18, color: Colors.black),
  ),
)

 
🔸 Material 3에서 사용되는 새로운 Typography 스타일(bodyLarge) 적용
🔸 폰트 설정도 추가하여 사용자가 쉽게 적용 가능하도록 개선
 
 
 
 
 


4️⃣ Material Theme을 활용한 전체 테마 설정

 
📌 Material 3 테마 적용 가능 (useMaterial3: true)
📌 버튼, 카드 등 UI 요소의 스타일을 일괄 지정 가능

 

📌 Material Theme 예제

ThemeData(
  useMaterial3: true,
  elevatedButtonTheme: ElevatedButtonThemeData(
    style: ElevatedButton.styleFrom(
      backgroundColor: Colors.blue,
      foregroundColor: Colors.white,
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
    ),
  ),
)

🔸 버튼 스타일을 일괄적으로 지정 가능
🔸 Material 3 디자인을 지원하여 최신 UI 적용
 
 
📌 활용 예제

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Material 3 테마 예제',
      theme: ThemeData(
        //useMaterial3: true, // ✅ Material 3 디자인 적용
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue), // 기본 색상
        elevatedButtonTheme: ElevatedButtonThemeData(
          style: ElevatedButton.styleFrom(
            backgroundColor: Colors.blue, // 버튼 배경색
            foregroundColor: Colors.white, // 버튼 텍스트 색상
            padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
            shape:
                RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
          ),
        ),
        floatingActionButtonTheme: const FloatingActionButtonThemeData(
          backgroundColor: Colors.blue,
          foregroundColor: Colors.white,
        ),
        cardTheme: CardTheme(
          color: Colors.white,
          shadowColor: Colors.grey.withValues(alpha: 0.5),
          shape:
              RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
        ),
      ),
      darkTheme: ThemeData.dark().copyWith(
        elevatedButtonTheme: ElevatedButtonThemeData(
          style: ElevatedButton.styleFrom(
            backgroundColor: Colors.orange,
            foregroundColor: Colors.black,
          ),
        ),
      ),
      themeMode: ThemeMode.system, // ✅ 시스템 설정에 따라 라이트/다크 모드 자동 변경
      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context); // 현재 테마 가져오기

    return Scaffold(
      appBar: AppBar(
        title: const Text('Material 3 테마 적용'),
        backgroundColor: theme.colorScheme.primary,
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () {},
              child: const Text('테마 적용 버튼'),
            ),
            const SizedBox(height: 20),
            Card(
              elevation: 4,
              child: Padding(
                padding: const EdgeInsets.all(16.0),
                child: Text(
                  '이것은 Material 3 디자인을 적용한 카드입니다.',
                  style: theme.textTheme.bodyLarge,
                ),
              ),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {},
        child: const Icon(Icons.add),
      ),
    );
  }
}

 
📌 Material 3 테스트 결과


 
 
 
 
 
 


5️⃣ 다크 모드 지원

 
📌 ThemeData.dark()를 활용하여 다크 모드 지원
📌 MediaQuery를 사용하여 시스템 테마 감지 가능

 

 
📌  다크 모드 자동 감지 적용

MaterialApp(
  themeMode: ThemeMode.system,
  theme: ThemeData.light(),
  darkTheme: ThemeData.dark(),
)

 
🔸 시스템 설정(다크/라이트)에 따라 자동으로 변경
🔸 사용자가 직접 변경하는 기능도 추가 가능
 
 
📌 활용 예제 코드

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

// ✅ MyApp을 StatefulWidget으로 변경하여 themeMode 상태 관리
class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  MyAppState 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(
      debugShowCheckedModeBanner: false,
      title: '다크 모드 지원 앱',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue), // 라이트 모드 색상
        textTheme:
            const TextTheme(bodyLarge: TextStyle(fontSize: 18)), // 기본 텍스트 스타일
      ),
      darkTheme: ThemeData.dark().copyWith(
        textTheme: const TextTheme(
            bodyLarge: TextStyle(fontSize: 18)), // 다크 모드에서도 동일한 폰트 크기 적용
      ),
      themeMode: _themeMode, // 현재 테마 적용
      home: HomeScreen(toggleTheme: toggleTheme),
    );
  }
}

// ✅ HomeScreen에서 버튼을 눌러 다크 모드 변경
class HomeScreen extends StatelessWidget {
  final VoidCallback toggleTheme;

  const HomeScreen({super.key, required this.toggleTheme});

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final isDarkMode = theme.brightness == Brightness.dark;

    return Scaffold(
      appBar: AppBar(
        title: const Text('다크 모드 테스트'),
        backgroundColor: theme.colorScheme.primary,
        actions: [
          IconButton(
            icon: Icon(isDarkMode ? Icons.wb_sunny : Icons.nightlight_round),
            onPressed: toggleTheme, // 버튼 클릭 시 테마 변경
          ),
        ],
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(
              isDarkMode ? Icons.nightlight_round : Icons.wb_sunny,
              size: 80,
              color: theme.colorScheme.secondary,
            ),
            const SizedBox(height: 10),
            Text(
              isDarkMode ? '다크 모드 활성화됨' : '라이트 모드 활성화됨',
              style: theme.textTheme.bodyLarge,
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: toggleTheme, // 버튼으로 다크 모드 변경
              child: const Text('라이트/다크 모드 변경'),
            ),
          ],
        ),
      ),
    );
  }
}

 
 
📌 다크 모드 테스트 결과


 
 
 
 
 
 


📌 오늘의 요약

✅ ColorScheme을 활용하여 앱의 색상 테마를 설정하는 방법 학습
✅ Typography를 활용하여 텍스트 스타일을 통일하는 방법 이해
✅ Material Theme을 활용하여 버튼, 카드 스타일을 일괄 변경하는 방법 실습
✅ 다크 모드를 감지하여 자동 적용하는 기능 구현
✅ 사용자가 직접 다크 모드를 변경하는 기능 추가
 
 
 
 
 
 


🔥 오늘 배운 핵심 내용 정리

🎨 ColorScheme → 앱의 색상 테마를 한 곳에서 설정하는 방법
🔤 Typography → 텍스트 스타일을 일괄 적용하는 방법
🛠️ Material Theme → 버튼, 카드 등의 스타일을 전체적으로 통일
🌙 다크 모드 적용 → ThemeMode.system을 활용해 자동 변경
 

728x90
반응형