Menu
CoddyTech

Den Speicherort des Zustands wählen

Teil des Abschnitts State Management der Flutter-Journey von Coddy. Lektion 21 von 27.

Der Schalter für den dunklen Modus auf dem Einstellungsbildschirm bewegt sich, aber nichts wird dunkel. Sein Wert bleibt dank setState erhalten, und nur der Schalter kann ihn sehen. Das Theme wird weit entfernt davon in MyApp festgelegt. Dieser Wert gehört zur gesamten App.

Jeder Wert in einer App braucht einen Ort. Überlege, wer ihn verwendet:

  • Ein Widget (der Text eines Felds, ein geöffnetes Panel, ein Tab-Index): setState in diesem Widget.
  • Ein paar nahe beieinanderliegende Widgets (eine Schaltfläche und die Beschriftung daneben): Verschiebe den Wert in ihr übergeordnetes Widget und gib ihn weiter.
  • Viele Widgets oder mehrere Bildschirme (der Benutzer, ein Warenkorb, die Einstellungen): ein gemeinsames Modell mit Provider oder Riverpod.

Provider oder Riverpod? Mit beiden lässt sich die Aufgabe erledigen. Provider ist etwas einfacher und platziert Modelle im Widget-Baum, wo sie über context gefunden werden. Riverpod hält Provider außerhalb des Baums, sodass ein Wert kein context benötigt und Provider einander beobachten können. Entscheide dich für eine Variante für eine App und verwende sie überall.

Hier eignet sich ein StateProvider: ein bool, den MyApp liest, um das Theme auszuwählen, und den der Schalter ändert:

final darkModeProvider = StateProvider((ref) => false);

// in MyApp, jetzt ein ConsumerWidget:
themeMode: ref.watch(darkModeProvider) ? ThemeMode.dark : ThemeMode.light,
challenge icon

Aufgabe

Schwer

Sorge dafür, dass der Schalter für den Dunkelmodus die gesamte App ändert:

  • Füge oben final darkModeProvider = StateProvider((ref) => false); hinzu.
  • Wandle MyApp in ein ConsumerWidget um, dessen themeMode dem Provider folgt.
  • Wandle SettingsScreen in ein ConsumerWidget um: Der Schalter zeigt den Wert des Providers an und setzt ihn bei einer Änderung.

Probier es selbst

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

void main() {
  runApp(const ProviderScope(child: MyApp()));
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData.light(),
      darkTheme: ThemeData.dark(),
      themeMode: ThemeMode.light,
      home: const HomePage(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Notes'),
        actions: [
          IconButton(
            icon: const Icon(Icons.settings),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(builder: (context) => const SettingsScreen()),
              );
            },
          ),
        ],
      ),
      body: const Center(child: Text('No notes yet')),
    );
  }
}

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

  @override
  State<SettingsScreen> createState() => _SettingsScreenState();
}

class _SettingsScreenState extends State<SettingsScreen> {
  bool dark = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Settings')),
      body: ListView(
        children: [
          SwitchListTile(
            title: const Text('Dark mode'),
            value: dark,
            onChanged: (value) {
              setState(() {
                dark = value;
              });
            },
          ),
        ],
      ),
    );
  }
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in State Management

Übe selbstständig: Online-Flutter-Compiler