Warna Dinamis dan Tema Terang atau Gelap Adaptif
Sesuaikan palet dengan wallpaper pengguna dan beralih dengan mulus antara mode terang dan gelap.
Warna Dinamis dan Tema Terang atau Gelap Adaptif adalah pelajaran Flutter Mobile Development gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Flutter Mobile Development, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Flutter Mobile Development mencakup 4 pelajaran total.
Bagian dari pelajaran ini belum diterjemahkan dan ditampilkan dalam bahasa Inggris.
Why Dynamic Color Matters
Material 3 introduced dynamic color: an app's palette can be derived from the user's wallpaper (Android 12+) so your UI feels personal and native to the device.
- On supported devices, the system exposes a
ColorSchemesourced from the wallpaper. - On older devices or other platforms, you fall back to a brand seed color.
- The same logic must produce both a light and a dark scheme.
In this lesson you'll wire up dynamic color, build adaptive light/dark themes, and let the system decide which one to show.
Seed Color as the Foundation
Even with dynamic color, you always need a fallback. Material 3's ColorScheme.fromSeed generates a full, accessible palette from a single seed color.
- Pass
brightnessto get the matching light or dark variant. - The generated scheme guarantees correct contrast between roles like
primaryandonPrimary.
import 'package:flutter/material.dart';
final ColorScheme lightScheme = ColorScheme.fromSeed(
seedColor: const Color(0xFF6750A4),
brightness: Brightness.light,
);
final ColorScheme darkScheme = ColorScheme.fromSeed(
seedColor: const Color(0xFF6750A4),
brightness: Brightness.dark,
);Building Light and Dark ThemeData
A ThemeData wraps a ColorScheme plus typography and component styles. With Material 3 you set useMaterial3: true and feed in the scheme.
- Create one
ThemeDataper brightness. - Keep them consistent by deriving both from the same seed.
ThemeData buildTheme(ColorScheme scheme) {
return ThemeData(
useMaterial3: true,
colorScheme: scheme,
appBarTheme: AppBarTheme(
backgroundColor: scheme.surface,
foregroundColor: scheme.onSurface,
),
);
}Letting the System Pick the Mode
MaterialApp accepts both a theme (light) and a darkTheme. The themeMode property decides which is active.
ThemeMode.systemfollows the OS setting automatically.ThemeMode.light/ThemeMode.darkforce a mode (useful for an in-app toggle).
With ThemeMode.system, Flutter switches seamlessly when the user flips dark mode in their device settings.
MaterialApp(
theme: buildTheme(lightScheme),
darkTheme: buildTheme(darkScheme),
themeMode: ThemeMode.system,
home: const HomePage(),
);Reading Dynamic Color from the System
The dynamic_color package exposes the wallpaper-based palette via the DynamicColorBuilder widget. Its builder gives you optional light and dark ColorSchemes.
- If the device supports dynamic color, both schemes are non-null.
- If not, they are
nulland you fall back to your seed.
import 'package:dynamic_color/dynamic_color.dart';
import 'package:flutter/material.dart';
DynamicColorBuilder(
builder: (ColorScheme? lightDynamic, ColorScheme? darkDynamic) {
final light = lightDynamic ?? lightScheme;
final dark = darkDynamic ?? darkScheme;
return MaterialApp(
theme: buildTheme(light),
darkTheme: buildTheme(dark),
themeMode: ThemeMode.system,
home: const HomePage(),
);
},
);Harmonizing Brand Colors
When you blend dynamic wallpaper colors with your brand color, the two can clash. The harmonize helpers shift a custom color toward the dynamic primary so accents feel cohesive.
- Use
harmonizeWithon aColoragainst the scheme's primary. - This keeps custom semantic colors (success, warning) on-brand with the wallpaper.
import 'package:dynamic_color/dynamic_color.dart';
import 'package:flutter/material.dart';
ColorScheme harmonizeScheme(ColorScheme scheme) {
return scheme.harmonized();
}
Color harmonizeBrand(Color brand, ColorScheme scheme) {
return brand.harmonizeWith(scheme.primary);
}Color Roles, Not Hard-Coded Hex
For themes to adapt, widgets must read semantic roles from Theme.of(context).colorScheme instead of hard-coded colors.
scheme.primarywithscheme.onPrimaryfor prominent actions.scheme.surfacewithscheme.onSurfacefor backgrounds and text.scheme.surfaceContainerHighestfor subtle cards.
Because these roles flip with brightness, your widgets become light/dark agnostic automatically.
Widget buildCard(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
return Container(
color: scheme.surfaceContainerHighest,
child: Text(
'Adaptive',
style: TextStyle(color: scheme.onSurface),
),
);
}Pure Dart: Picking a Scheme by Brightness
The decision logic for which scheme to use is plain Dart. Here is a tiny, runnable model of the fallback rule: prefer the dynamic scheme, otherwise use the seed-derived one.
- This mirrors the
lightDynamic ?? lightSchemepattern. - No Flutter widgets needed — just the selection rule.
enum Brightness { light, dark }
String chooseScheme({
required Brightness brightness,
required bool supportsDynamic,
}) {
final base = supportsDynamic ? 'dynamic' : 'seed';
return '$base-${brightness.name}';
}
void main() {
print(chooseScheme(brightness: Brightness.dark, supportsDynamic: true));
print(chooseScheme(brightness: Brightness.light, supportsDynamic: false));
}An In-App Theme Toggle
Users often want to override the system. Store a ThemeMode in state and pass it to MaterialApp. A ValueNotifier is a lightweight way to rebuild on change.
- Default to
ThemeMode.systemso wallpaper/dark-mode still apply. - Let the toggle pick light, dark, or back to system.
final themeModeNotifier = ValueNotifier<ThemeMode>(ThemeMode.system);
ValueListenableBuilder<ThemeMode>(
valueListenable: themeModeNotifier,
builder: (context, mode, _) {
return MaterialApp(
theme: buildTheme(lightScheme),
darkTheme: buildTheme(darkScheme),
themeMode: mode,
home: const HomePage(),
);
},
);Reacting to the Effective Brightness
Inside widgets you sometimes need to know which mode is actually rendering (for example, to pick a different illustration). Read it from the active theme, not from the device, because an in-app toggle may override the system.
Theme.of(context).brightnessreflects the resolved theme.- Avoid
MediaQuery.platformBrightnessOfwhen a toggle can override it.
Widget heroImage(BuildContext context) {
final isDark = Theme.of(context).brightness == Brightness.dark;
return Image.asset(
isDark ? 'assets/hero_dark.png' : 'assets/hero_light.png',
);
}Testing Both Modes Quickly
Always verify your UI in both schemes before shipping. Two practical habits:
- Toggle dark mode in the device/emulator settings to confirm
ThemeMode.systemreacts. - Temporarily force
themeMode: ThemeMode.darkto catch hard-coded colors and low-contrast text.
Common bugs: a hard-coded Colors.black text that vanishes on a dark surface, or a custom accent that never harmonized with the dynamic palette.
Quick Check: Choosing themeMode
You want your app to automatically match the user's wallpaper-based dynamic colors AND follow their OS light/dark setting, while still allowing an optional in-app override later. What is the right baseline configuration?
Recap: Adaptive Material 3 Theming
You built a palette that adapts to both wallpaper and brightness:
- Seed fallback:
ColorScheme.fromSeedfor light and dark when dynamic color is unavailable. - Dynamic color:
DynamicColorBuildersupplies wallpaper schemes, with?? seedSchemefallback. - Harmonization: blend brand and custom colors toward the dynamic primary.
- Semantic roles: read
colorSchemeroles instead of hard-coded hex so widgets flip automatically. - Mode control:
themeMode: ThemeMode.systemby default, with an optionalValueNotifiertoggle.
Adapt to the user, fall back gracefully, and never hard-code a color you could read from the scheme.
Belajar Dart dengan tutor AI — gratis
Tulis dan jalankan kode asli di browser kamu, dapatkan bantuan instan dari tutor AI 24/7, dan lanjutkan di mana kamu tinggalkan di web atau aplikasi.
- Kursus
- 22
- Pelajaran
- 88
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Warna Dinamis dan Tema Terang atau Gelap Adaptif” gratis?
Ya — teks lengkap “Warna Dinamis dan Tema Terang atau Gelap Adaptif” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Flutter Mobile Development, upgrade ke CoddyKit PRO. Kursus Flutter Mobile Development mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Warna Dinamis dan Tema Terang atau Gelap Adaptif”?
Sesuaikan palet dengan wallpaper pengguna dan beralih dengan mulus antara mode terang dan gelap. Kamu berlatih Flutter Mobile Development dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai Flutter Mobile Development?
Tidak diperlukan pengalaman sebelumnya. Flutter Mobile Development di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.
Berapa lama pelajaran “Warna Dinamis dan Tema Terang atau Gelap Adaptif” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran Flutter Mobile Development ini?
Ya. Setiap pelajaran Flutter Mobile Development menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Skema Warna Material 3 dan Warna Seed
- Warna Dinamis dan Tema Terang atau Gelap Adaptif
- ThemeExtension Khusus untuk Token Merek
- Tipografi Responsif dan Tema Komponen