Wybór miejsca przechowywania stanu
Część sekcji Zarządzanie stanem ścieżki Flutter w Coddy. Lekcja 21 z 27.
Przełącznik trybu ciemnego na ekranie Settings się przesuwa, ale nic nie staje się ciemne. Zachowuje swoją wartość dzięki setState, ale tylko przełącznik ma do niej dostęp. Motyw jest ustawiany w zupełnie innym miejscu — w MyApp. Ta wartość dotyczy całej aplikacji.
Każda wartość w aplikacji potrzebuje swojego miejsca. Zastanów się, kto z niej korzysta:
- Jeden widżet (tekst pola, otwarty panel, indeks karty):
setStatew tym widżecie. - Kilka pobliskich widżetów (przycisk i etykieta obok niego): przenieś tę wartość do ich widżetu nadrzędnego i przekaż ją dalej.
- Wiele widżetów lub kilka ekranów (użytkownik, koszyk, ustawienia): współdzielony model z Provider lub Riverpod.
Provider czy Riverpod? Oba rozwiązania spełniają swoje zadanie. Provider jest nieco prostszy i umieszcza modele w drzewie widżetów, gdzie można je znaleźć przez context. Riverpod przechowuje providery poza drzewem, więc wartość nie potrzebuje context, a providery mogą obserwować siebie nawzajem. Wybierz jedno rozwiązanie dla aplikacji i używaj go wszędzie.
W tym przypadku pasuje StateProvider: jedna wartość bool, odczytywana przez MyApp w celu wybrania motywu i zmieniana przez przełącznik:
final darkModeProvider = StateProvider((ref) => false);
// w MyApp, teraz ConsumerWidget:
themeMode: ref.watch(darkModeProvider) ? ThemeMode.dark : ThemeMode.light,Wyzwanie
TrudnySpraw, aby przełącznik trybu ciemnego zmieniał wygląd całej aplikacji:
- Dodaj na górze
final darkModeProvider = StateProvider((ref) => false);. - Zmień
MyAppw widżetConsumerWidget, któregothemeModezależy od dostawcy. - Zmień
SettingsScreenw widżetConsumerWidget: przełącznik wyświetla wartość dostawcy i ustawia ją po zmianie.
Spróbuj swoich sił
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;
});
},
),
],
),
);
}
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Zarządzanie stanem
1Przenoszenie stanu w górę
Przekazywanie stanu do komponentu potomnegoPrzekazywanie funkcji zwrotnej do komponentu potomnegoFunkcje zwrotne przekazujące wartośćPrzenoszenie stanu w górę4Riverpod
Riverpod: ProviderScopeConsumerWidget i ref.watchRiverpod: StateProviderRiverpod: NotifierDostawcy obserwujący innych dostawcówWybór miejsca przechowywania stanuPoćwicz samodzielnie: Kompilator Flutter online