點燈坊

失くすものさえない今が強くなるチャンスよ

自訂 Light Mode 與 Dark Mode

Sam Xiao's Avatar 2024-10-02

Flutter 的 MaterialApp 支援 Theme,可分別自訂 Light Mode 與 Dark Mode 的顏色。

Version

Flutter 3.24

Flutter

custom01

  • Android 與 iOS 都成功顯示 Light Mode 與 Dark Mode

Main

main.dart

import 'package:flutter/material.dart';

import 'constants/dark_mode.dart';
import 'constants/light_mode.dart';
import 'home.dart';

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

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
        theme: ThemeData(
          useMaterial3: true,
          colorScheme: lightMode,
        ),
        darkTheme: ThemeData(
          useMaterial3: true,
          colorScheme: darkMode,
        ),
        home: const Home());
  }
}
  • 建立 MyApp widget 並傳入 runApp() 顯示

Line 3

import 'constants/dark_mode.dart';
import 'constants/light_mode.dart';
  • 引用 dark_modelight_mode 顏色設定常數

Line 14


Widget build(BuildContext context) {
  return MaterialApp(
      theme: ThemeData(
        useMaterial3: true,
        colorScheme: lightMode,
      ),
      darkTheme: ThemeData(
        useMaterial3: true,
        colorScheme: darkMode,
      ),
      home: const Home());
}
  • theme:設定 light mode 主題
  • dartTheme:設定 dark mode 主題
  • useMaterial3: true:使用 Material 3
  • colorScheme:指定自行設定的 lightModedarkMode 常數

Custom Color

constants/light_mode.dart

import 'package:flutter/material.dart';

var lightMode = const ColorScheme.light().copyWith(
  primary: const Color(0xFFFF0000),
  onPrimary: const Color(0xFFFFFFFF),
);
  • ColorSheme.light().copyWith():從內建 light mode 複製出預設色票,並加入新的自訂 primaryonPrimary 的顏色

constants/dark_moke.dart

import 'package:flutter/material.dart';

var darkMode = const ColorScheme.dark().copyWith(
  primary: const Color(0xFF0000FF),
  onPrimary: const Color(0xFFFFFFFF),
);
  • ColorSheme.dark().copyWith():從內建 dark mode 複製出預設色票,並加入新的 primaryonPrimary 的顏色

Counter

counter.dart

import 'package:flutter/material.dart';

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

  
  State<Home> createState() {
    return _Home();
  }
}

class _Home extends State<Home> {
  var _count = 0;

  void _onPressed() {
    setState(() => _count++);
  }

  
  Widget build(BuildContext context) {
    var appBar = AppBar(title: const Text('Counter'));

    var floatingActionButton = FloatingActionButton(
      onPressed: _onPressed,
      backgroundColor: Theme.of(context).colorScheme.primary,
      foregroundColor: Theme.of(context).colorScheme.onPrimary,
      child: const Icon(Icons.add),
    );

    var body = Center(child: Text('$_count'));

    return Scaffold(
      appBar: appBar,
      floatingActionButton: floatingActionButton,
      body: body,
    );
  }
}
  • 普通的 Stateful Widget 寫法

Line 23

floatingActionButton: FloatingActionButton(
  onPressed: _onPressed,
  backgroundColor: Theme.of(context).colorScheme.primary,
  foregroundColor: Theme.of(context).colorScheme.onPrimary,
  child: const Icon(Icons.add),
),
  • backgroundColor:由 Theme.of(context) 取得目前是 light mode 或 dark mode,再從 colorScheme 取得 primary 顏色
  • foregroundColor:由 Theme.of(context) 取得目前是 light mode 或 dark mode,再從 colorScheme 取得 onPrimary 顏色

Conclusion

  • 實現自訂 light mode 與 dark mode 並不難,只要在自訂的 light_modedark_mode 常數設定 顏色,且在最外層的 MyApp widget 的 themedarkTheme,且由 Theme.of(context).colorScheme.primary 取得 Material Design 的顏色

Reference

Nidhi Sorathiya, Illuminating the Dark Canvas: The Definitive Guide to Implementing Flutter Dark Mode