Flutter Mobile Development · Pelajaran

Warna Dinamis dan Tema Terang atau Gelap Adaptif

Sesuaikan palet dengan wallpaper pengguna dan beralih dengan mulus antara mode terang dan gelap.

Pelajaran 2 dari 413 langkah

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 ColorScheme sourced 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 brightness to get the matching light or dark variant.
  • The generated scheme guarantees correct contrast between roles like primary and onPrimary.
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 ThemeData per 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.system follows the OS setting automatically.
  • ThemeMode.light / ThemeMode.dark force 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 null and 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 harmonizeWith on a Color against 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.primary with scheme.onPrimary for prominent actions.
  • scheme.surface with scheme.onSurface for backgrounds and text.
  • scheme.surfaceContainerHighest for 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 ?? lightScheme pattern.
  • 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.system so 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).brightness reflects the resolved theme.
  • Avoid MediaQuery.platformBrightnessOf when 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.system reacts.
  • Temporarily force themeMode: ThemeMode.dark to 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.fromSeed for light and dark when dynamic color is unavailable.
  • Dynamic color: DynamicColorBuilder supplies wallpaper schemes, with ?? seedScheme fallback.
  • Harmonization: blend brand and custom colors toward the dynamic primary.
  • Semantic roles: read colorScheme roles instead of hard-coded hex so widgets flip automatically.
  • Mode control: themeMode: ThemeMode.system by default, with an optional ValueNotifier toggle.

Adapt to the user, fall back gracefully, and never hard-code a color you could read from the scheme.

Gratis untuk memulai

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

  1. Skema Warna Material 3 dan Warna Seed
  2. Warna Dinamis dan Tema Terang atau Gelap Adaptif
  3. ThemeExtension Khusus untuk Token Merek
  4. Tipografi Responsif dan Tema Komponen
← Kembali ke Flutter Mobile Development