본문 바로가기
Flutter

[Flutter] App에 Light/Dark Theme을 설정 및 변경하는 방법

by haku-s 2024. 8. 22.
728x90

Flutter에서 Application의 Theme을 System(Device)에 적용된 Theme을 가져오고 이를 통해 실행되는 앱의 Light or Dark Mode의 Theme을 설정하고 그 값을 가지고 유저의 설정으로 모드를 다시 변경하는 옵션을 추가할 수 있다.

 

다음은 예제는 system theme을 가져와 현재 brightness mode를 theme으로 설정하는 방법이다.

class App extends StatefulWidget {
  const App({super.key});

  @override
  State<App> createState() => _AppState();
}

class _AppState extends State<App> {
  ThemeMode _themeMode = ThemeMode.system;

  @override
  void initState() {
    super.initState();
    _themeMode = WidgetsBinding.instance.window.platformBrightness == Brightness.dark ? ThemeMode.dark : ThemeMode.light;
  }

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        useMaterial3: true,
      ),
      darkTheme: ThemeData.dark(),
      themeMode: _themeMode,
      home: HomeScreen(toggleTheme: _toggleTheme, themeMode: _themeMode),
    );
  }
}

추가로 HomeScreen Widget을 만들어 유저 이벤트가 발생하면  _toggleTheme()을 호출하여 Mode가 반전되도록 설정하였다.

 

Flutter  v3.7.0-32.0.pre. 이전에서는 "WidgetsBinding.instance.window.platformBrightness"으로 Brightness.dark or Brightness.light를 얻을 수 있었다. 그 이후로는 동작은 하나 다음과 같은 메시지로 권장되지 않는다.

'window' is deprecated and shouldn't be used. Look up the current FlutterView from the context via View.of(context) or consult the PlatformDispatcher directly instead. Deprecated to prepare for the upcoming multi-window support. This feature was deprecated after v3.7.0-32.0.pre.
Try replacing the use of the deprecated member with the replacement.

 

"WidgetsBinding.instance.window.platformBrightness" 를 "PlatformDispatcher.instance.platformBrightness"로 변경해서 사용하도록 한다.

_themeMode = PlatformDispatcher.instance.platformBrightness == Brightness.dark ? ThemeMode.dark : ThemeMode.light;

PlatformDispatcher는 import 'package:flutter/foundation.dart'; 사용이 요구된다.

 

iOS의 UI를 사용하는 Cupertino의 경우 다음과 같이 theme의 brightness를 설정해 주면 된다.

CupertinoApp(
  theme: CupertinoThemeData(
    brightness: _themeMode == ThemeMode.dark ? Brightness.dark : Brightness.light,
  ),
  ...
);

 

간단한 예제의 전체 코드는 다음과 같다.

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

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

class App extends StatefulWidget {
  const App({super.key});

  @override
  State<App> createState() => _AppState();
}

class _AppState extends State<App> {
  ThemeMode _themeMode = ThemeMode.system;

  @override
  void initState() {
    super.initState();
    _themeMode =
        PlatformDispatcher.instance.platformBrightness == Brightness.dark
            ? ThemeMode.dark
            : ThemeMode.light;
  }

  void _toggleTheme() {
    setState(() {
      _themeMode =
          _themeMode == ThemeMode.dark ? ThemeMode.light : ThemeMode.dark;
    });
  }

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        useMaterial3: true,
      ),
      darkTheme: ThemeData.dark(), // 다크 테마 설정
      themeMode: _themeMode, // 테마 모드 적용
      home: HomeScreen(toggleTheme: _toggleTheme, themeMode: _themeMode),
    );
  }
}

class HomeScreen extends StatelessWidget {
  final VoidCallback toggleTheme;
  final ThemeMode themeMode;

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Center(
          child: ListTile(
            leading: Icon(themeMode == ThemeMode.dark
                ? Icons.dark_mode
                : Icons.light_mode),
            title:
                Text(themeMode == ThemeMode.dark ? 'Dark Mode' : 'Light Mode'),
            onTap: () {
              toggleTheme();
            },
          ),
        ),
      ),
    );
  }
}
728x90