בחירת המקום שבו המצב נשמר
חלק מהיחידה ניהול מצב במסלול ה-Flutter של Coddy. שיעור 21 מתוך 27.
מתג המצב הכהה במסך ההגדרות זז, אבל שום דבר לא הופך לכהה. הוא שומר את הערך שלו באמצעות setState, ורק המתג יכול לראות אותו. ערכת הנושא מוגדרת הרחק ממנו, בתוך MyApp. הערך הזה שייך לאפליקציה כולה.
כל ערך באפליקציה זקוק למקום משלו. שאלו מי משתמש בו:
- רכיב אחד (טקסט של שדה, לוח פתוח, אינדקס של כרטיסייה):
setStateבאותו רכיב. - כמה רכיבים סמוכים (כפתור והתווית שלצדו): מעלים את הערך לרכיב האב שלהם ומעבירים אותו הלאה.
- רכיבים רבים או כמה מסכים (המשתמש, עגלת קניות, ההגדרות): מודל משותף באמצעות Provider או Riverpod.
Provider או Riverpod? שניהם עושים את העבודה. Provider מעט פשוט יותר וממקם מודלים בעץ הרכיבים, שם אפשר למצוא אותם באמצעות context. Riverpod שומר את הספקים מחוץ לעץ, כך שערך אינו זקוק ל־context, וספקים יכולים לעקוב זה אחר זה. בחרו אחד עבור האפליקציה והשתמשו בו בכל מקום.
כאן מתאים StateProvider: ערך bool אחד, שנקרא על ידי MyApp כדי לבחור את ערכת הנושא ומשתנה על ידי המתג:
final darkModeProvider = StateProvider((ref) => false);
// בתוך MyApp, שכעת הוא ConsumerWidget:
themeMode: ref.watch(darkModeProvider) ? ThemeMode.dark : ThemeMode.light,אתגר
קשההפוך את מתג המצב הכהה לכזה שמשנה את כל האפליקציה:
- הוסף בראש הקובץ את
final darkModeProvider = StateProvider((ref) => false);. - הפוך את
MyAppל־ConsumerWidgetשה־themeModeשלו נקבע בהתאם לספק. - הפוך את
SettingsScreenל־ConsumerWidget: המתג מציג את ערך הספק ומעדכן אותו כשהערך משתנה.
נסו בעצמכם
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;
});
},
),
],
),
);
}
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה ניהול מצב
1העלאת מצב למעלה
העברת מצב לרכיב ילדהעברת פונקציית Callback לרכיב ילדפונקציות Callback ששולחות ערךהעלאת מצב למעלה4Riverpod
Riverpod: ProviderScopeConsumerWidget ו־ref.watchRiverpod: StateProviderRiverpod: Notifierספקים שעוקבים אחר ספקיםבחירת המקום שבו המצב נשמרתרגלו בעצמכם: קומפיילר Flutter אונליין