τα στοιχεία επικοινωνίας μου
Ταχυδρομείο[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Πίνακας περιεχομένων
1. Η σημασία της τοπικής ανανέωσης
2. Διάφοροι τρόποι εφαρμογής μερικής ανανέωσης
1. Χρησιμοποιήστε τη μέθοδο setState για μερική ανανέωση
2. Χρησιμοποιήστε το StatefulWidget και το InheritedWidget για μερική ανανέωση της διεπαφής χρήστη
3.ValueNotifier和ValueListenableBuilder
7. Χρησιμοποιήστε το GlobalKey
Στο Flutter, η διαχείριση κατάστασης αναφέρεται στον τρόπο διαχείρισης και ενημέρωσης της κατάστασης δεδομένων στην εφαρμογή και ενημέρωσης της διεπαφής χρήστη σύμφωνα με τις αλλαγές στην κατάσταση. Η αποτελεσματική διαχείριση κατάστασης μπορεί να βοηθήσει τους προγραμματιστές να δημιουργήσουν πιο αποτελεσματικές και διατηρούμενες εφαρμογές.
Το setState είναι η πιο βασική μέθοδος διαχείρισης κατάστασης στο Flutter Όταν αλλάξει η κατάσταση, το πλαίσιο θα ειδοποιηθεί για την εκ νέου κατασκευή της διεπαφής χρήστη. Φυσικά, γνωρίζουμε ότι όταν καλούμε τη μέθοδο setState, η σελίδα θα επανασχεδιαστεί μεγαλύτερη απόδοση.
Ποιες μέθοδοι υπάρχουν λοιπόν στο Flutter για μερική ανανέωση της διεπαφής χρήστη Αυτό το ιστολόγιο παραθέτει διάφορους τρόπους για την εφαρμογή μερικής ανανέωσης του Flutter;
Η μερική ανανέωση αναφέρεται στην ανανέωση μόνο μέρους της διεπαφής και όχι ολόκληρης της σελίδας. Αυτό βελτιώνει την απόδοση και την εμπειρία χρήστη.
Το setState είναι η πιο συχνά χρησιμοποιούμενη μέθοδος διαχείρισης κατάστασης στο Flutter. Χρησιμοποιείται για την ειδοποίηση του πλαισίου των αλλαγών κατάστασης, που οδηγούν στην ανακατασκευή της διεπαφής.
Όταν δημιουργούμε ένα έργο Flutter, το παράδειγμα του χρονοδιακόπτη που δημιουργείται από το σύστημα από προεπιλογή είναι το παράδειγμα της μερικής ανανέωσης setState.
- import 'package:flutter/material.dart';
-
- class SetStateMainPage extends StatefulWidget {
- final String title;
- const SetStateMainPage({super.key, required this.title});
-
- @override
- State<SetStateMainPage> createState() => _SetStateMainPageMainPageState();
- }
-
- class _SetStateMainPageMainPageState extends State<SetStateMainPage> {
- int _count = 0;
-
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: Text(widget.title),
- ),
- body: Center(
- child: Text(
- '您点击了$_count次',
- style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
- ),
- ),
- floatingActionButton: FloatingActionButton(
- child: const Icon(Icons.add),
- onPressed: () {
- setState(() {
- _count++;
- });
- },
- )
- );
- }
- }
Εικόνα 1.setState μερική ανανέωση
Όταν η σελίδα είναι σχετικά απλή, μπορείτε να χρησιμοποιήσετε απευθείας τη μέθοδο setState για μερική ανανέωση της διεπαφής χρήστη.
Σενάρια χρήσης: απλές αλλαγές κατάστασης, όπως πλήθος κλικ κουμπιών, κατάσταση αλλαγής κ.λπ.
Προφυλάξεις:
StatefulWidget
είναι ένα συστατικό με κατάσταση,InheritedWidget
Χρησιμοποιείται για την κοινή χρήση δεδομένων εντός του δέντρου στοιχείων.
Όταν χρειάζεται να μοιραστούμε δεδομένα, μπορούμε να εξετάσουμε το StatefulWidget και το InheritedWidget για μερική ανανέωση της διεπαφής χρήστη.
Ο πλήρης κώδικας έχει ως εξής:
Εικόνα 2. Ανανεώστε τη διεπαφή χρήστη με κοινή χρήση δεδομένων
- import 'package:flutter/material.dart';
-
- class MyInheritedWidget extends InheritedWidget {
- final int counter;
- const MyInheritedWidget({
- super.key,
- required this.counter,
- required super.child,
- });
- @override
- bool updateShouldNotify(covariant InheritedWidget oldWidget) {
- return true;
- }
- static MyInheritedWidget? of(BuildContext context) {
- return context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();
- }
- }
-
- class InheritedWidgetPage extends StatefulWidget {
- final String title;
- const InheritedWidgetPage({super.key, required this.title});
-
- @override
- State<InheritedWidgetPage> createState() => _InheritedWidgetPageState();
- }
-
- class _InheritedWidgetPageState extends State<InheritedWidgetPage> {
- int counter = 0;
- void _incrementCounter() {
- setState(() {
- counter++;
- });
- }
-
- @override
- Widget build(BuildContext context) {
- return MyInheritedWidget(
- counter: counter,
- child: Scaffold(
- appBar: AppBar(
- title: Text(widget.title),
- ),
- body: Center(child: Column(
- children: [
- const Divider(),
- const CounterDisplay(),
- const SizedBox(height: 20),
- ElevatedButton(
- onPressed: _incrementCounter,
- child: const Text('add'),
- ),
- ],
- ),),
- ),
- );
- }
- }
-
- class CounterDisplay extends StatelessWidget {
- const CounterDisplay({super.key});
- @override
- Widget build(BuildContext context) {
- final inheritedWidget = MyInheritedWidget.of(context);
- return Text('点击次数: ${inheritedWidget?.counter}');
- }
- }
Τα κύρια σενάρια χρήσης αυτής της μεθόδου είναι τα εξής: κατά την κοινή χρήση κατάστασης στο δέντρο στοιχείων, όπως θέμα, ρυθμίσεις γλώσσας κ.λπ.
Το πλεονέκτημα είναι ότι η κοινή χρήση δεδομένων είναι βολική και η εισαγωγή κώδικα
Το μειονέκτημα είναι ότι είναι πολύπλοκο στη χρήση και μπορεί να επηρεαστεί η απόδοση.
ValueNotifier
Είναι ένα απλό εργαλείο διαχείρισης κατάστασης,ValueListenableBuilder
για παρακολούθησηValueNotifier
Η αλλαγή.
Η χρήση είναι επίσης πολύ απλή:
1. Δημιουργήστε Instantier ValueNotifier
2. Το αντικείμενο Widget που πρόκειται να παρακολουθηθεί είναι τυλιγμένο με ValueListenableBuilder
3. Τρόπος αλλαγής δεδομένων που προκαλούνται από συμβάντα
Σε σύγκριση με τις προηγούμενες μεθόδους, αυτή η μέθοδος είναι πολύ απλή και εύκολη στη χρήση και η απόδοσή της είναι επίσης πολύ υψηλή.
Μειονεκτήματα: Μπορεί να χειριστεί μόνο απλές αλλαγές κατάστασης
Ο πλήρης κώδικας έχει ως εξής:
- import 'package:flutter/material.dart';
-
- class ValueNotifierPage extends StatefulWidget {
- final String title;
- const ValueNotifierPage({super.key, required this.title});
-
- @override
- State<ValueNotifierPage> createState() => _ValueNotifierPageState();
- }
-
- class _ValueNotifierPageState extends State<ValueNotifierPage> {
-
- final ValueNotifier<int> _counter = ValueNotifier<int>(0);
-
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: Text(widget.title),
- ),
- body: Center(
- child: ValueListenableBuilder<int>(
- valueListenable: _counter,
- builder: (context, value, child) {
- return Text(
- '您点击了$value次',
- style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
- );
- },
- )
- ),
- floatingActionButton: FloatingActionButton(
- child: const Icon(Icons.add),
- onPressed: () {
- _counter.value ++;
- },
- )
- );
- }
- }
Το Stream είναι ένα αντικείμενο που χρησιμοποιείται για την παράδοση ασύγχρονων συμβάντων και τα συμβάντα μπορούν να σταλούν μέσω του StreamController. Όπου χρειάζεται να ανανεώσετε τη διεπαφή χρήστη, μπορείτε να στείλετε ένα συμβάν στη ροή και, στη συνέχεια, να χρησιμοποιήσετε το StreamBuilder για να ακούσετε τη ροή Όταν ληφθεί ένα νέο συμβάν, το StreamBuilder θα αναδημιουργήσει αυτόματα τη διεπαφή χρήστη. Αυτή η μέθοδος είναι κατάλληλη για καταστάσεις όπου πρέπει να παρακολουθούνται πολλαπλά ασύγχρονα συμβάντα.
Όταν χρειάζεται να επεξεργαστούμε ασύγχρονες ροές δεδομένων, όπως αιτήματα δικτύου, δεδομένα σε πραγματικό χρόνο κ.λπ., μπορούμε να εξετάσουμε το ενδεχόμενο χρήσης του StreamBuilder. Για παράδειγμα, στο ακόλουθο παράδειγμα, γράψαμε μια ασύγχρονη μέθοδο που προσομοιώνει ένα αίτημα δικτύου Όταν το αίτημα δικτύου δεν επιστρέφει το σωστό αποτέλεσμα, μπορούμε να φορτώσουμε τη γραμμή προόδου.
Το πλεονέκτημα αυτής της μεθόδου είναι ότι μπορεί να ελέγχει τα ασύγχρονα αιτήματα με μεγαλύτερη ακρίβεια, όπως την κατάσταση των αιτημάτων δικτύου κ.λπ. Ωστόσο, το Dior είναι πιο περίπλοκο και μπορεί να απαιτεί περισσότερο κώδικα.
Ο πλήρης κώδικας έχει ως εξής:
- import 'dart:async';
- import 'package:flutter/material.dart';
-
- class StreamBuilderRefreshUIPage extends StatefulWidget {
- final String title;
- const StreamBuilderRefreshUIPage({super.key, required this.title});
-
- @override
- State<StreamBuilderRefreshUIPage> createState() =>
- _StreamBuilderRefreshUIPageState();
- }
-
- class _StreamBuilderRefreshUIPageState extends State<StreamBuilderRefreshUIPage> {
- late Future<String> _data;
-
- Future<String> fetchData() async {
- // 模拟网络请求延迟
- await Future.delayed(const Duration(seconds: 2));
- // 返回模拟数据
- return 'Hello, Flutter!';
- }
-
- @override
- void initState() {
- // TODO: implement initState
- super.initState();
- _data = fetchData();
- }
-
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: Text(widget.title),
- ),
- body: Center(
- child: FutureBuilder<String>(
- future: _data,
- builder: (context, snapshot) {
- if (snapshot.connectionState == ConnectionState.waiting) {
- return const CircularProgressIndicator();
- } else if (snapshot.hasError) {
- return Text('Error: ${snapshot.error}');
- } else {
- return Text('Data: ${snapshot.data}');
- }
- },
- ),
- ),
- floatingActionButton: FloatingActionButton(
- onPressed: fetchData,
- tooltip: 'Increment',
- child: const Icon(Icons.add),
- ),
- );
- }
- }
Provider
Είναι μια λύση διαχείρισης κατάστασης που προτείνει η Flutter.Consumer
Χρησιμοποιείται για την ανάγνωση και την παρακολούθηση της κατάστασης.
Ας πάρουμε επίσης το χρονόμετρο ως παράδειγμα.
1. Πρώτα εισάγουμε Provider.
πάροχος: ^6.1.2
2. Προσαρμόστε την κλάση ChangeNotifier.
Το ChangeNotifier είναι μια απλή κατηγορία στο Flutter SDK. Χρησιμοποιείται για την αποστολή ειδοποιήσεων σε ακροατές. Με άλλα λόγια, εάν οριστεί ως ChangeNotifier, μπορείτε να εγγραφείτε στις αλλαγές κατάστασής του. (Αυτό είναι παρόμοιο με το γνωστό μοτίβο παρατηρητή).
Στον κώδικα που θέλουμε να εφαρμόσουμε, υπάρχουν δύο μεταβλητές _counter1 και _counter2 Ο κώδικας ορίζεται ως εξής:
- class CounterModel extends ChangeNotifier {
- int _counter1 = 0;
- int _counter2 = 0;
- void addCounter1(){
- debugPrint('counter:$_counter1');
- _counter1 += 1;
- notifyListeners();
- }
- void addCounter2(){
- debugPrint('counter:$_counter2');
- _counter2 += 1;
- notifyListeners();
- }
- }
3. Χρησιμοποιήστε το Customer για να τυλίξετε το Widget που θέλουμε να ανανεώσουμε
- Consumer<CounterModel>(
- builder: (context, counterModel, child) {
- return Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- Text('计数器1个数: ${counterModel._counter1}'),
- ElevatedButton(onPressed: (){
- counterModel.addCounter1();
- }, child: const Icon(Icons.add),),
- ],
- );
- },
- ),
4. Ο πλήρης κώδικας έχει ως εξής:
- import 'package:flutter/material.dart';
- import 'package:provider/provider.dart';
-
- class ProviderRefreshPage extends StatefulWidget {
- final String title;
- const ProviderRefreshPage({super.key, required this.title});
-
- @override
- State<ProviderRefreshPage> createState() => _ProviderRefreshPageState();
- }
-
- class CounterModel extends ChangeNotifier {
- int _counter1 = 0;
- int _counter2 = 0;
- void addCounter1(){
- debugPrint('counter:$_counter1');
- _counter1 += 1;
- notifyListeners();
- }
- void addCounter2(){
- debugPrint('counter:$_counter2');
- _counter2 += 1;
- notifyListeners();
- }
- }
-
- class _ProviderRefreshPageState extends State<ProviderRefreshPage> {
-
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: Text(widget.title),
- ),
- body: Center(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.start,
- children: <Widget>[
- const SizedBox(height: 10,), // 添加一些间距
- const Divider(),
- const Text('计数器实例',style: TextStyle(fontSize: 12,fontWeight: FontWeight.bold),),
- Consumer<CounterModel>(
- builder: (context, counterModel, child) {
- return Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- Text('计数器1个数: ${counterModel._counter1}'),
- ElevatedButton(onPressed: (){
- counterModel.addCounter1();
- }, child: const Icon(Icons.add),),
- ],
- );
- },
- ),
-
- Consumer<CounterModel>(
- builder: (context, counterModel, child) {
- return Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- Text('计数器1个数: ${counterModel._counter2}'),
- ElevatedButton(onPressed: (){
- counterModel.addCounter2();
- }, child: const Icon(Icons.add),),
- ],
- );
- },
- ),
- const Divider(height: 20,),
- ],
- ),
- ),
- );
- }
- }
Μπορούμε επίσης να χρησιμοποιήσουμε το GetX για να εφαρμόσουμε μερική ανανέωση της διεπαφής χρήστη.
Πρώτη εγκατάσταση του GetX:
get: ^4.6.6
Στη συνέχεια, ενσωματώνουμε τις μεταβλητές στο GetxController.
- class CounterManagerController extends GetxController {
- final counter1 = 0.obs;
- final counter2 = 0.obs;
- void incrementCount1() {
- counter1.value++;
- }
- void incrementCount2() {
- counter2.value++;
- }
- }
Στη συνέχεια, χρησιμοποιήστε το Obx για να τυλίξετε το Widget που χρειάζεται να εμφανίζει λογική.
Obx(()=> Κείμενο('Αριθμός μετρητή 1: ${controller.counter2.value}'))
Ο πλήρης κώδικας έχει ως εξής:
- import 'package:flutter/material.dart';
- import 'package:get/get.dart';
-
-
- class CounterManagerController extends GetxController {
- final counter1 = 0.obs;
- final counter2 = 0.obs;
- void incrementCount1() {
- counter1.value++;
- }
- void incrementCount2() {
- counter2.value++;
- }
- }
-
- class GetXRefreshUIPage extends StatelessWidget {
- final String title;
- const GetXRefreshUIPage({super.key, required this.title});
-
- @override
- Widget build(BuildContext context) {
- final CounterManagerController controller = Get.put(CounterManagerController());
- return Scaffold(
- appBar: AppBar(
- title: Text(title),
- ),
- body: Center(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.start,
- children: <Widget>[
- const SizedBox(
- height: 10,
- ), // 添加一些间距
- const Divider(),
- const Text(
- '计数器实例',
- style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
- ),
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- Obx(()=> Text('计数器1个数: ${controller.counter1.value}')),
- ElevatedButton(
- onPressed: () {
- controller.incrementCount1();
- },
- child: const Icon(Icons.add),
- ),
- ],
- ),
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- Obx(()=> Text('计数器1个数: ${controller.counter2.value}')),
- ElevatedButton(
- onPressed: () {
- controller.incrementCount2();
- },
- child: const Icon(Icons.add),
- ),
- ],
- ),
- const Divider(
- height: 20,
- ),
- ],
- ),
- ),
- );
- }
- }
Φυσικά, υπάρχουν αρκετοί άλλοι τρόποι υλοποίησης μερικής ανανέωσης στο GetX. Μπορείτε να ρίξετε μια ματιά στην τεκμηρίωσή του. Εδώ είναι μόνο μια ιδέα υλοποίησης.
Οι παραπάνω τρεις μέθοδοι υλοποίησης υλοποιούνται όλες μέσω του πλαισίου. Εάν δεν θέλετε να εισαγάγετε αυτό το πλαίσιο, μπορούμε να χρησιμοποιήσουμε το GlobalKey για να εφαρμόσουμε τη λειτουργία μερικής ανανέωσης του περιβάλλοντος χρήστη.
Ένα κλειδί που είναι μοναδικό σε όλη την εφαρμογή Το GlobalKey προσδιορίζει μοναδικά στοιχεία, όπως π.χBuildContext
.ΓιαStatefulWidgets
, παρέχει επίσης το GlobalKeyState
Πρόσβαση.
Στην επίδειξη του χρονοδιακόπτη, εάν ανανεώσουμε μερικώς τη διεπαφή χρήστη μέσω του GlobalKey, πρώτα βγάζουμε το Widget για μερική ανανέωση και το ενσωματώνουμε σε ένα ξεχωριστό στοιχείο.
Ο πλήρης κώδικας είναι ο ακόλουθος Ενσωματώνουμε το Widget για μερική ανανέωση και παρέχουμε μια διεπαφή για την ανανέωση των εσωτερικών δεδομένων, onPressed.
- class CounterText extends StatefulWidget {
- const CounterText(Key key) : super(key: key);
- @override
- State<StatefulWidget> createState() {
- return CounterTextState();
- }
- }
-
- class CounterTextState extends State<CounterText> {
- String _text="0";
-
- @override
- Widget build(BuildContext context) {
- return Center(
- child: Text(_text,style: const TextStyle(fontSize: 20),),
- );
- }
- void onPressed(int count) {
- setState(() {
- _text = count.toString();
- });
- }
- }
Στη συνέχεια, δημιουργήστε το GlobaKey στην κύρια διεπαφή μας:
- int _count = 0;
- int _count2 = 0;
- GlobalKey<CounterTextState> textKey = GlobalKey();
- GlobalKey<CounterTextState> textKey2 = GlobalKey();
Σε περίπτωση που πρέπει να ανανεωθεί η διεπαφή χρήστη, καλέστε τη διεπαφή που παρέχεται στο προηγούμενο βήμα μέσω του GlobalKey και κάντε ανανέωση.
Ο πλήρης κώδικας έχει ως εξής:
- import 'package:flutter/material.dart';
-
- class GlobalKeyRefreshPage extends StatefulWidget {
- final String title;
- const GlobalKeyRefreshPage({super.key, required this.title});
-
- @override
- State<GlobalKeyRefreshPage> createState() => _GlobalKeyRefreshPageState();
- }
-
- class _GlobalKeyRefreshPageState extends State<GlobalKeyRefreshPage> {
- int _count = 0;
- int _count2 = 0;
- //包裹你定义的需要更新的weight
- GlobalKey<CounterTextState> textKey = GlobalKey();
- GlobalKey<CounterTextState> textKey2 = GlobalKey();
-
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: Text(widget.title),
- ),
- body: Center(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.start,
- children: <Widget>[
- const SizedBox(
- height: 10,
- ), // 添加一些间距
- const Divider(),
- const Text(
- '计数器实例',
- style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
- ),
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- CounterText(textKey),
- ElevatedButton(
- onPressed: () {
- _count++;
- textKey.currentState?.onPressed(_count);
- },
- child: const Icon(Icons.add),
- ),
- ],
- ),
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- CounterText(textKey2),
- ElevatedButton(
- onPressed: () {
- _count2++;
- textKey2.currentState?.onPressed(_count2);
- },
- child: const Icon(Icons.add),
- ),
- ],
- ),
- const Divider(
- height: 20,
- ),
- ],
- ),
- ),
- );
- }
- }
-
-
- class CounterText extends StatefulWidget {
- const CounterText(Key key) : super(key: key);
- @override
- State<StatefulWidget> createState() {
- return CounterTextState();
- }
- }
-
- class CounterTextState extends State<CounterText> {
- String _text="0";
-
- @override
- Widget build(BuildContext context) {
- return Center(
- child: Text(_text,style: const TextStyle(fontSize: 20),),
- );
- }
- void onPressed(int count) {
- setState(() {
- _text = count.toString();
- });
- }
- }