Κοινή χρήση τεχνολογίας

Διάφοροι τρόποι για το Flutter να εφαρμόσει μερική ανανέωση

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Πίνακας περιεχομένων

Πρόλογος

1. Η σημασία της τοπικής ανανέωσης

1. Έννοια

2. Σημασία

2. Διάφοροι τρόποι εφαρμογής μερικής ανανέωσης

1. Χρησιμοποιήστε τη μέθοδο setState για μερική ανανέωση

2. Χρησιμοποιήστε το StatefulWidget και το InheritedWidget για μερική ανανέωση της διεπαφής χρήστη

3.ValueNotifier和ValueListenableBuilder

4.StreamBuilder

5.Παροχέας

6.GetX

7. Χρησιμοποιήστε το GlobalKey


Πρόλογος

Στο Flutter, η διαχείριση κατάστασης αναφέρεται στον τρόπο διαχείρισης και ενημέρωσης της κατάστασης δεδομένων στην εφαρμογή και ενημέρωσης της διεπαφής χρήστη σύμφωνα με τις αλλαγές στην κατάσταση. Η αποτελεσματική διαχείριση κατάστασης μπορεί να βοηθήσει τους προγραμματιστές να δημιουργήσουν πιο αποτελεσματικές και διατηρούμενες εφαρμογές.

Το setState είναι η πιο βασική μέθοδος διαχείρισης κατάστασης στο Flutter Όταν αλλάξει η κατάσταση, το πλαίσιο θα ειδοποιηθεί για την εκ νέου κατασκευή της διεπαφής χρήστη. Φυσικά, γνωρίζουμε ότι όταν καλούμε τη μέθοδο setState, η σελίδα θα επανασχεδιαστεί μεγαλύτερη απόδοση.

Ποιες μέθοδοι υπάρχουν λοιπόν στο Flutter για μερική ανανέωση της διεπαφής χρήστη Αυτό το ιστολόγιο παραθέτει διάφορους τρόπους για την εφαρμογή μερικής ανανέωσης του Flutter;

1. Η σημασία της τοπικής ανανέωσης

1. Έννοια

Η μερική ανανέωση αναφέρεται στην ανανέωση μόνο μέρους της διεπαφής και όχι ολόκληρης της σελίδας. Αυτό βελτιώνει την απόδοση και την εμπειρία χρήστη.

2. Σημασία

  1. Αποφύγετε τις περιττές επανασχεδιάσεις και βελτιώστε την απόδοση
  2. Παρέχετε μια πιο ομαλή εμπειρία χρήστη
  3. Μειώστε την κατανάλωση πόρων

2. Διάφοροι τρόποι εφαρμογής μερικής ανανέωσης

1. Χρησιμοποιήστε τη μέθοδο setState για μερική ανανέωση

Το setState είναι η πιο συχνά χρησιμοποιούμενη μέθοδος διαχείρισης κατάστασης στο Flutter. Χρησιμοποιείται για την ειδοποίηση του πλαισίου των αλλαγών κατάστασης, που οδηγούν στην ανακατασκευή της διεπαφής.

Όταν δημιουργούμε ένα έργο Flutter, το παράδειγμα του χρονοδιακόπτη που δημιουργείται από το σύστημα από προεπιλογή είναι το παράδειγμα της μερικής ανανέωσης setState.

  1. import 'package:flutter/material.dart';
  2. class SetStateMainPage extends StatefulWidget {
  3. final String title;
  4. const SetStateMainPage({super.key, required this.title});
  5. @override
  6. State<SetStateMainPage> createState() => _SetStateMainPageMainPageState();
  7. }
  8. class _SetStateMainPageMainPageState extends State<SetStateMainPage> {
  9. int _count = 0;
  10. @override
  11. Widget build(BuildContext context) {
  12. return Scaffold(
  13. appBar: AppBar(
  14. title: Text(widget.title),
  15. ),
  16. body: Center(
  17. child: Text(
  18. '您点击了$_count次',
  19. style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
  20. ),
  21. ),
  22. floatingActionButton: FloatingActionButton(
  23. child: const Icon(Icons.add),
  24. onPressed: () {
  25. setState(() {
  26. _count++;
  27. });
  28. },
  29. )
  30. );
  31. }
  32. }

Εικόνα 1.setState μερική ανανέωση

Όταν η σελίδα είναι σχετικά απλή, μπορείτε να χρησιμοποιήσετε απευθείας τη μέθοδο setState για μερική ανανέωση της διεπαφής χρήστη.

Σενάρια χρήσης: απλές αλλαγές κατάστασης, όπως πλήθος κλικ κουμπιών, κατάσταση αλλαγής κ.λπ.

Προφυλάξεις:

  1. Οι συχνές κλήσεις προς το setState ενδέχεται να προκαλέσουν προβλήματα απόδοσης
  2. Αποφύγετε την κλήση setState στη μέθοδο δημιουργίας

2. Χρησιμοποιήστε το StatefulWidget και το InheritedWidget για μερική ανανέωση της διεπαφής χρήστη

        StatefulWidget είναι ένα συστατικό με κατάσταση,InheritedWidget Χρησιμοποιείται για την κοινή χρήση δεδομένων εντός του δέντρου στοιχείων.

Όταν χρειάζεται να μοιραστούμε δεδομένα, μπορούμε να εξετάσουμε το StatefulWidget και το InheritedWidget για μερική ανανέωση της διεπαφής χρήστη.

Ο πλήρης κώδικας έχει ως εξής:

Εικόνα 2. Ανανεώστε τη διεπαφή χρήστη με κοινή χρήση δεδομένων

  1. import 'package:flutter/material.dart';
  2. class MyInheritedWidget extends InheritedWidget {
  3. final int counter;
  4. const MyInheritedWidget({
  5. super.key,
  6. required this.counter,
  7. required super.child,
  8. });
  9. @override
  10. bool updateShouldNotify(covariant InheritedWidget oldWidget) {
  11. return true;
  12. }
  13. static MyInheritedWidget? of(BuildContext context) {
  14. return context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();
  15. }
  16. }
  17. class InheritedWidgetPage extends StatefulWidget {
  18. final String title;
  19. const InheritedWidgetPage({super.key, required this.title});
  20. @override
  21. State<InheritedWidgetPage> createState() => _InheritedWidgetPageState();
  22. }
  23. class _InheritedWidgetPageState extends State<InheritedWidgetPage> {
  24. int counter = 0;
  25. void _incrementCounter() {
  26. setState(() {
  27. counter++;
  28. });
  29. }
  30. @override
  31. Widget build(BuildContext context) {
  32. return MyInheritedWidget(
  33. counter: counter,
  34. child: Scaffold(
  35. appBar: AppBar(
  36. title: Text(widget.title),
  37. ),
  38. body: Center(child: Column(
  39. children: [
  40. const Divider(),
  41. const CounterDisplay(),
  42. const SizedBox(height: 20),
  43. ElevatedButton(
  44. onPressed: _incrementCounter,
  45. child: const Text('add'),
  46. ),
  47. ],
  48. ),),
  49. ),
  50. );
  51. }
  52. }
  53. class CounterDisplay extends StatelessWidget {
  54. const CounterDisplay({super.key});
  55. @override
  56. Widget build(BuildContext context) {
  57. final inheritedWidget = MyInheritedWidget.of(context);
  58. return Text('点击次数: ${inheritedWidget?.counter}');
  59. }
  60. }

Τα κύρια σενάρια χρήσης αυτής της μεθόδου είναι τα εξής: κατά την κοινή χρήση κατάστασης στο δέντρο στοιχείων, όπως θέμα, ρυθμίσεις γλώσσας κ.λπ.

Το πλεονέκτημα είναι ότι η κοινή χρήση δεδομένων είναι βολική και η εισαγωγή κώδικα

Το μειονέκτημα είναι ότι είναι πολύπλοκο στη χρήση και μπορεί να επηρεαστεί η απόδοση.

3.ValueNotifier和ValueListenableBuilder

        ValueNotifier Είναι ένα απλό εργαλείο διαχείρισης κατάστασης,ValueListenableBuilder για παρακολούθησηValueNotifier Η αλλαγή.

Η χρήση είναι επίσης πολύ απλή:

1. Δημιουργήστε Instantier ValueNotifier

2. Το αντικείμενο Widget που πρόκειται να παρακολουθηθεί είναι τυλιγμένο με ValueListenableBuilder

3. Τρόπος αλλαγής δεδομένων που προκαλούνται από συμβάντα

Σε σύγκριση με τις προηγούμενες μεθόδους, αυτή η μέθοδος είναι πολύ απλή και εύκολη στη χρήση και η απόδοσή της είναι επίσης πολύ υψηλή.

Μειονεκτήματα: Μπορεί να χειριστεί μόνο απλές αλλαγές κατάστασης

Ο πλήρης κώδικας έχει ως εξής:

  1. import 'package:flutter/material.dart';
  2. class ValueNotifierPage extends StatefulWidget {
  3. final String title;
  4. const ValueNotifierPage({super.key, required this.title});
  5. @override
  6. State<ValueNotifierPage> createState() => _ValueNotifierPageState();
  7. }
  8. class _ValueNotifierPageState extends State<ValueNotifierPage> {
  9. final ValueNotifier<int> _counter = ValueNotifier<int>(0);
  10. @override
  11. Widget build(BuildContext context) {
  12. return Scaffold(
  13. appBar: AppBar(
  14. title: Text(widget.title),
  15. ),
  16. body: Center(
  17. child: ValueListenableBuilder<int>(
  18. valueListenable: _counter,
  19. builder: (context, value, child) {
  20. return Text(
  21. '您点击了$value次',
  22. style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
  23. );
  24. },
  25. )
  26. ),
  27. floatingActionButton: FloatingActionButton(
  28. child: const Icon(Icons.add),
  29. onPressed: () {
  30. _counter.value ++;
  31. },
  32. )
  33. );
  34. }
  35. }

4.StreamBuilder

Το Stream είναι ένα αντικείμενο που χρησιμοποιείται για την παράδοση ασύγχρονων συμβάντων και τα συμβάντα μπορούν να σταλούν μέσω του StreamController. Όπου χρειάζεται να ανανεώσετε τη διεπαφή χρήστη, μπορείτε να στείλετε ένα συμβάν στη ροή και, στη συνέχεια, να χρησιμοποιήσετε το StreamBuilder για να ακούσετε τη ροή Όταν ληφθεί ένα νέο συμβάν, το StreamBuilder θα αναδημιουργήσει αυτόματα τη διεπαφή χρήστη. Αυτή η μέθοδος είναι κατάλληλη για καταστάσεις όπου πρέπει να παρακολουθούνται πολλαπλά ασύγχρονα συμβάντα.

Όταν χρειάζεται να επεξεργαστούμε ασύγχρονες ροές δεδομένων, όπως αιτήματα δικτύου, δεδομένα σε πραγματικό χρόνο κ.λπ., μπορούμε να εξετάσουμε το ενδεχόμενο χρήσης του StreamBuilder. Για παράδειγμα, στο ακόλουθο παράδειγμα, γράψαμε μια ασύγχρονη μέθοδο που προσομοιώνει ένα αίτημα δικτύου Όταν το αίτημα δικτύου δεν επιστρέφει το σωστό αποτέλεσμα, μπορούμε να φορτώσουμε τη γραμμή προόδου.

Το πλεονέκτημα αυτής της μεθόδου είναι ότι μπορεί να ελέγχει τα ασύγχρονα αιτήματα με μεγαλύτερη ακρίβεια, όπως την κατάσταση των αιτημάτων δικτύου κ.λπ. Ωστόσο, το Dior είναι πιο περίπλοκο και μπορεί να απαιτεί περισσότερο κώδικα.

Ο πλήρης κώδικας έχει ως εξής:

  1. import 'dart:async';
  2. import 'package:flutter/material.dart';
  3. class StreamBuilderRefreshUIPage extends StatefulWidget {
  4. final String title;
  5. const StreamBuilderRefreshUIPage({super.key, required this.title});
  6. @override
  7. State<StreamBuilderRefreshUIPage> createState() =>
  8. _StreamBuilderRefreshUIPageState();
  9. }
  10. class _StreamBuilderRefreshUIPageState extends State<StreamBuilderRefreshUIPage> {
  11. late Future<String> _data;
  12. Future<String> fetchData() async {
  13. // 模拟网络请求延迟
  14. await Future.delayed(const Duration(seconds: 2));
  15. // 返回模拟数据
  16. return 'Hello, Flutter!';
  17. }
  18. @override
  19. void initState() {
  20. // TODO: implement initState
  21. super.initState();
  22. _data = fetchData();
  23. }
  24. @override
  25. Widget build(BuildContext context) {
  26. return Scaffold(
  27. appBar: AppBar(
  28. title: Text(widget.title),
  29. ),
  30. body: Center(
  31. child: FutureBuilder<String>(
  32. future: _data,
  33. builder: (context, snapshot) {
  34. if (snapshot.connectionState == ConnectionState.waiting) {
  35. return const CircularProgressIndicator();
  36. } else if (snapshot.hasError) {
  37. return Text('Error: ${snapshot.error}');
  38. } else {
  39. return Text('Data: ${snapshot.data}');
  40. }
  41. },
  42. ),
  43. ),
  44. floatingActionButton: FloatingActionButton(
  45. onPressed: fetchData,
  46. tooltip: 'Increment',
  47. child: const Icon(Icons.add),
  48. ),
  49. );
  50. }
  51. }

5.Παροχέας

       Provider Είναι μια λύση διαχείρισης κατάστασης που προτείνει η Flutter.Consumer Χρησιμοποιείται για την ανάγνωση και την παρακολούθηση της κατάστασης.

Ας πάρουμε επίσης το χρονόμετρο ως παράδειγμα.

1. Πρώτα εισάγουμε Provider.

πάροχος: ^6.1.2

2. Προσαρμόστε την κλάση ChangeNotifier.

Το ChangeNotifier είναι μια απλή κατηγορία στο Flutter SDK. Χρησιμοποιείται για την αποστολή ειδοποιήσεων σε ακροατές. Με άλλα λόγια, εάν οριστεί ως ChangeNotifier, μπορείτε να εγγραφείτε στις αλλαγές κατάστασής του. (Αυτό είναι παρόμοιο με το γνωστό μοτίβο παρατηρητή).

Στον κώδικα που θέλουμε να εφαρμόσουμε, υπάρχουν δύο μεταβλητές _counter1 και _counter2 Ο κώδικας ορίζεται ως εξής:

  1. class CounterModel extends ChangeNotifier {
  2. int _counter1 = 0;
  3. int _counter2 = 0;
  4. void addCounter1(){
  5. debugPrint('counter:$_counter1');
  6. _counter1 += 1;
  7. notifyListeners();
  8. }
  9. void addCounter2(){
  10. debugPrint('counter:$_counter2');
  11. _counter2 += 1;
  12. notifyListeners();
  13. }
  14. }

3. Χρησιμοποιήστε το Customer για να τυλίξετε το Widget που θέλουμε να ανανεώσουμε

  1. Consumer<CounterModel>(
  2. builder: (context, counterModel, child) {
  3. return Row(
  4. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  5. children: [
  6. Text('计数器1个数: ${counterModel._counter1}'),
  7. ElevatedButton(onPressed: (){
  8. counterModel.addCounter1();
  9. }, child: const Icon(Icons.add),),
  10. ],
  11. );
  12. },
  13. ),

4. Ο πλήρης κώδικας έχει ως εξής:

  1. import 'package:flutter/material.dart';
  2. import 'package:provider/provider.dart';
  3. class ProviderRefreshPage extends StatefulWidget {
  4. final String title;
  5. const ProviderRefreshPage({super.key, required this.title});
  6. @override
  7. State<ProviderRefreshPage> createState() => _ProviderRefreshPageState();
  8. }
  9. class CounterModel extends ChangeNotifier {
  10. int _counter1 = 0;
  11. int _counter2 = 0;
  12. void addCounter1(){
  13. debugPrint('counter:$_counter1');
  14. _counter1 += 1;
  15. notifyListeners();
  16. }
  17. void addCounter2(){
  18. debugPrint('counter:$_counter2');
  19. _counter2 += 1;
  20. notifyListeners();
  21. }
  22. }
  23. class _ProviderRefreshPageState extends State<ProviderRefreshPage> {
  24. @override
  25. Widget build(BuildContext context) {
  26. return Scaffold(
  27. appBar: AppBar(
  28. title: Text(widget.title),
  29. ),
  30. body: Center(
  31. child: Column(
  32. mainAxisAlignment: MainAxisAlignment.start,
  33. children: <Widget>[
  34. const SizedBox(height: 10,), // 添加一些间距
  35. const Divider(),
  36. const Text('计数器实例',style: TextStyle(fontSize: 12,fontWeight: FontWeight.bold),),
  37. Consumer<CounterModel>(
  38. builder: (context, counterModel, child) {
  39. return Row(
  40. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  41. children: [
  42. Text('计数器1个数: ${counterModel._counter1}'),
  43. ElevatedButton(onPressed: (){
  44. counterModel.addCounter1();
  45. }, child: const Icon(Icons.add),),
  46. ],
  47. );
  48. },
  49. ),
  50. Consumer<CounterModel>(
  51. builder: (context, counterModel, child) {
  52. return Row(
  53. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  54. children: [
  55. Text('计数器1个数: ${counterModel._counter2}'),
  56. ElevatedButton(onPressed: (){
  57. counterModel.addCounter2();
  58. }, child: const Icon(Icons.add),),
  59. ],
  60. );
  61. },
  62. ),
  63. const Divider(height: 20,),
  64. ],
  65. ),
  66. ),
  67. );
  68. }
  69. }

6.GetX

Μπορούμε επίσης να χρησιμοποιήσουμε το GetX για να εφαρμόσουμε μερική ανανέωση της διεπαφής χρήστη.

Πρώτη εγκατάσταση του GetX:

get: ^4.6.6

Στη συνέχεια, ενσωματώνουμε τις μεταβλητές στο GetxController.

  1. class CounterManagerController extends GetxController {
  2. final counter1 = 0.obs;
  3. final counter2 = 0.obs;
  4. void incrementCount1() {
  5. counter1.value++;
  6. }
  7. void incrementCount2() {
  8. counter2.value++;
  9. }
  10. }

Στη συνέχεια, χρησιμοποιήστε το Obx για να τυλίξετε το Widget που χρειάζεται να εμφανίζει λογική.

Obx(()=&gt; Κείμενο('Αριθμός μετρητή 1: ${controller.counter2.value}'))

Ο πλήρης κώδικας έχει ως εξής:

  1. import 'package:flutter/material.dart';
  2. import 'package:get/get.dart';
  3. class CounterManagerController extends GetxController {
  4. final counter1 = 0.obs;
  5. final counter2 = 0.obs;
  6. void incrementCount1() {
  7. counter1.value++;
  8. }
  9. void incrementCount2() {
  10. counter2.value++;
  11. }
  12. }
  13. class GetXRefreshUIPage extends StatelessWidget {
  14. final String title;
  15. const GetXRefreshUIPage({super.key, required this.title});
  16. @override
  17. Widget build(BuildContext context) {
  18. final CounterManagerController controller = Get.put(CounterManagerController());
  19. return Scaffold(
  20. appBar: AppBar(
  21. title: Text(title),
  22. ),
  23. body: Center(
  24. child: Column(
  25. mainAxisAlignment: MainAxisAlignment.start,
  26. children: <Widget>[
  27. const SizedBox(
  28. height: 10,
  29. ), // 添加一些间距
  30. const Divider(),
  31. const Text(
  32. '计数器实例',
  33. style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
  34. ),
  35. Row(
  36. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  37. children: [
  38. Obx(()=> Text('计数器1个数: ${controller.counter1.value}')),
  39. ElevatedButton(
  40. onPressed: () {
  41. controller.incrementCount1();
  42. },
  43. child: const Icon(Icons.add),
  44. ),
  45. ],
  46. ),
  47. Row(
  48. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  49. children: [
  50. Obx(()=> Text('计数器1个数: ${controller.counter2.value}')),
  51. ElevatedButton(
  52. onPressed: () {
  53. controller.incrementCount2();
  54. },
  55. child: const Icon(Icons.add),
  56. ),
  57. ],
  58. ),
  59. const Divider(
  60. height: 20,
  61. ),
  62. ],
  63. ),
  64. ),
  65. );
  66. }
  67. }

Φυσικά, υπάρχουν αρκετοί άλλοι τρόποι υλοποίησης μερικής ανανέωσης στο GetX. Μπορείτε να ρίξετε μια ματιά στην τεκμηρίωσή του. Εδώ είναι μόνο μια ιδέα υλοποίησης.

7. Χρησιμοποιήστε το GlobalKey

Οι παραπάνω τρεις μέθοδοι υλοποίησης υλοποιούνται όλες μέσω του πλαισίου. Εάν δεν θέλετε να εισαγάγετε αυτό το πλαίσιο, μπορούμε να χρησιμοποιήσουμε το GlobalKey για να εφαρμόσουμε τη λειτουργία μερικής ανανέωσης του περιβάλλοντος χρήστη.

Ένα κλειδί που είναι μοναδικό σε όλη την εφαρμογή Το GlobalKey προσδιορίζει μοναδικά στοιχεία, όπως π.χBuildContext .ΓιαStatefulWidgets, παρέχει επίσης το GlobalKeyStateΠρόσβαση.

Στην επίδειξη του χρονοδιακόπτη, εάν ανανεώσουμε μερικώς τη διεπαφή χρήστη μέσω του GlobalKey, πρώτα βγάζουμε το Widget για μερική ανανέωση και το ενσωματώνουμε σε ένα ξεχωριστό στοιχείο.

Ο πλήρης κώδικας είναι ο ακόλουθος Ενσωματώνουμε το Widget για μερική ανανέωση και παρέχουμε μια διεπαφή για την ανανέωση των εσωτερικών δεδομένων, onPressed.

  1. class CounterText extends StatefulWidget {
  2. const CounterText(Key key) : super(key: key);
  3. @override
  4. State<StatefulWidget> createState() {
  5. return CounterTextState();
  6. }
  7. }
  8. class CounterTextState extends State<CounterText> {
  9. String _text="0";
  10. @override
  11. Widget build(BuildContext context) {
  12. return Center(
  13. child: Text(_text,style: const TextStyle(fontSize: 20),),
  14. );
  15. }
  16. void onPressed(int count) {
  17. setState(() {
  18. _text = count.toString();
  19. });
  20. }
  21. }

Στη συνέχεια, δημιουργήστε το GlobaKey στην κύρια διεπαφή μας:

  1. int _count = 0;
  2. int _count2 = 0;
  3. GlobalKey<CounterTextState> textKey = GlobalKey();
  4. GlobalKey<CounterTextState> textKey2 = GlobalKey();

Σε περίπτωση που πρέπει να ανανεωθεί η διεπαφή χρήστη, καλέστε τη διεπαφή που παρέχεται στο προηγούμενο βήμα μέσω του GlobalKey και κάντε ανανέωση.

Ο πλήρης κώδικας έχει ως εξής:

  1. import 'package:flutter/material.dart';
  2. class GlobalKeyRefreshPage extends StatefulWidget {
  3. final String title;
  4. const GlobalKeyRefreshPage({super.key, required this.title});
  5. @override
  6. State<GlobalKeyRefreshPage> createState() => _GlobalKeyRefreshPageState();
  7. }
  8. class _GlobalKeyRefreshPageState extends State<GlobalKeyRefreshPage> {
  9. int _count = 0;
  10. int _count2 = 0;
  11. //包裹你定义的需要更新的weight
  12. GlobalKey<CounterTextState> textKey = GlobalKey();
  13. GlobalKey<CounterTextState> textKey2 = GlobalKey();
  14. @override
  15. Widget build(BuildContext context) {
  16. return Scaffold(
  17. appBar: AppBar(
  18. title: Text(widget.title),
  19. ),
  20. body: Center(
  21. child: Column(
  22. mainAxisAlignment: MainAxisAlignment.start,
  23. children: <Widget>[
  24. const SizedBox(
  25. height: 10,
  26. ), // 添加一些间距
  27. const Divider(),
  28. const Text(
  29. '计数器实例',
  30. style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
  31. ),
  32. Row(
  33. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  34. children: [
  35. CounterText(textKey),
  36. ElevatedButton(
  37. onPressed: () {
  38. _count++;
  39. textKey.currentState?.onPressed(_count);
  40. },
  41. child: const Icon(Icons.add),
  42. ),
  43. ],
  44. ),
  45. Row(
  46. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  47. children: [
  48. CounterText(textKey2),
  49. ElevatedButton(
  50. onPressed: () {
  51. _count2++;
  52. textKey2.currentState?.onPressed(_count2);
  53. },
  54. child: const Icon(Icons.add),
  55. ),
  56. ],
  57. ),
  58. const Divider(
  59. height: 20,
  60. ),
  61. ],
  62. ),
  63. ),
  64. );
  65. }
  66. }
  67. class CounterText extends StatefulWidget {
  68. const CounterText(Key key) : super(key: key);
  69. @override
  70. State<StatefulWidget> createState() {
  71. return CounterTextState();
  72. }
  73. }
  74. class CounterTextState extends State<CounterText> {
  75. String _text="0";
  76. @override
  77. Widget build(BuildContext context) {
  78. return Center(
  79. child: Text(_text,style: const TextStyle(fontSize: 20),),
  80. );
  81. }
  82. void onPressed(int count) {
  83. setState(() {
  84. _text = count.toString();
  85. });
  86. }
  87. }