개발일기

✨ Flutter 위젯 시리즈: Theme & Dark Mode 완전 정복

뱅우 2025. 7. 17. 10:16
반응형

플러터 앱을 조금 더 프로답게 만들고 싶다면?
꼭 알아야 할 것이 바로 Theme 관리Dark Mode입니다!
디자인 시스템의 핵심, ThemeData를 제대로 써보세요.


✅ 1️⃣ ThemeData 기본 구조

플러터는 기본적으로 ThemeData를 통해 앱의 컬러, 폰트, 버튼 스타일 등을 한 번에 설정할 수 있습니다.


MaterialApp(
  theme: ThemeData(
    primarySwatch: Colors.blue,
    textTheme: TextTheme(
      bodyLarge: TextStyle(fontSize: 18),
    ),
    elevatedButtonTheme: ElevatedButtonThemeData(
      style: ElevatedButton.styleFrom(
        backgroundColor: Colors.blue,
      ),
    ),
  ),
  home: MyHomePage(),
)

✔️ 앱 전체에 공통된 스타일을 입히고 유지보수를 쉽게 만듭니다.


✅ 2️⃣ 다크 모드 적용

플러터는 기본적으로 다크 모드를 지원합니다.
darkTheme를 추가하고, themeMode로 모드를 설정하면 끝!


MaterialApp(
  theme: ThemeData.light(),
  darkTheme: ThemeData.dark(),
  themeMode: ThemeMode.system, // 시스템 모드 따름
  home: MyHomePage(),
)

✔️ ThemeMode.system : 디바이스 모드를 따라감
✔️ ThemeMode.light : 강제로 라이트 모드
✔️ ThemeMode.dark : 강제로 다크 모드


✅ 3️⃣ 커스텀 다크 테마 예시

기본 ThemeData.dark() 대신 직접 색상을 커스텀할 수 있습니다.


ThemeData darkTheme = ThemeData(
  brightness: Brightness.dark,
  primaryColor: Colors.deepPurple,
  scaffoldBackgroundColor: Colors.black,
  textTheme: TextTheme(
    bodyLarge: TextStyle(color: Colors.white),
  ),
);

✔️ 디자인 시스템과 맞는 색상으로 커스텀해보세요!


✅ 4️⃣ Theme.of(context) 사용하기

위젯에서 현재 테마 색상이나 스타일을 가져오고 싶다면?


Container(
  color: Theme.of(context).primaryColor,
  child: Text(
    'Theme Color!',
    style: Theme.of(context).textTheme.bodyLarge,
  ),
)

✔️ Theme.of(context)로 현재 테마 속성에 접근할 수 있습니다.


✅ 실무 팁: Theme Extension

기본 ThemeData로 부족하다면 extension으로 커스텀 속성을 확장할 수 있습니다.


// 1) Extension 정의
@immutable
class CustomColors extends ThemeExtension<CustomColors> {
  final Color? brandColor;
  final Color? danger;

  const CustomColors({this.brandColor, this.danger});

  @override
  CustomColors copyWith({Color? brandColor, Color? danger}) {
    return CustomColors(
      brandColor: brandColor ?? this.brandColor,
      danger: danger ?? this.danger,
    );
  }

  @override
  CustomColors lerp(ThemeExtension<CustomColors>? other, double t) {
    if (other is! CustomColors) return this;
    return CustomColors(
      brandColor: Color.lerp(brandColor, other.brandColor, t),
      danger: Color.lerp(danger, other.danger, t),
    );
  }
}

// 2) Theme에 추가
ThemeData(
  extensions: [
    const CustomColors(
      brandColor: Colors.purple,
      danger: Colors.red,
    ),
  ],
)

// 3) 사용
final customColors = Theme.of(context).extension<CustomColors>()!;
Container(
  color: customColors.brandColor,
)

✔️ 확장성을 고려한 디자인 시스템 구현이 가능합니다!


📌 다음 편 예고

  • 👉 Flutter 상태관리 패턴 비교: Provider vs Riverpod vs Bloc
반응형