Menu
CoddyTech

Scegliere dove risiede lo stato

Fa parte della sezione Gestione dello stato del percorso Flutter di Coddy. Lezione 21 di 27.

L'interruttore della modalità scura nella schermata Impostazioni si sposta, ma niente diventa scuro. Mantiene il proprio valore con setState, e solo l'interruttore può vederlo. Il tema viene impostato altrove, in MyApp. Questo valore appartiene all'intera app.

Ogni valore in un'app ha bisogno di una casa. Chiediti chi lo usa:

  • Un solo widget (il testo di un campo, un pannello aperto, l'indice di una scheda): setState in quel widget.
  • Alcuni widget vicini (un pulsante e l'etichetta accanto): spostalo nel loro genitore e passalo ai widget figli.
  • Molti widget o più schermate (l'utente, un carrello, le impostazioni): un modello condiviso con Provider o Riverpod.

Provider o Riverpod? Entrambi svolgono il compito. Provider è un po' più semplice e inserisce i modelli nell'albero dei widget, dove vengono trovati tramite context. Riverpod mantiene i provider fuori dall'albero, quindi un valore non ha bisogno di context e i provider possono osservarsi a vicenda. Scegline uno per un'app e usalo ovunque.

Qui è adatto un StateProvider: un bool, letto da MyApp per scegliere il tema e modificato dall'interruttore:

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

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

Sfida

Difficile

Fai in modo che l'interruttore della modalità scura cambi l'intera app:

  • Aggiungi final darkModeProvider = StateProvider((ref) => false); in cima.
  • Trasforma MyApp in un ConsumerWidget il cui themeMode segue il provider.
  • Trasforma SettingsScreen in un ConsumerWidget: l'interruttore mostra il valore del provider e lo imposta quando cambia.

Provalo tu

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 iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Gestione dello stato

Esercitati da solo: Compilatore Flutter online