Flutter - State Management إدارة الحالة فلاطر

 Flutter - State Management إدارة الحالة فلاطر

Flutter - State Management إدارة الحالة فلاطر

Flutter - State Management إدارة الحالة فلاطر

باستخدام أسلوب StatefulWidget و setState (). يبدأ الالتباس الحقيقي عندما نريد تطبيق حالة التطبيق حيث توجد طرق عديدة لتحقيق ذلك.

في هذه المقالة ، سنحاول فهم الاختلافات الرئيسية في خيارات إدارة الحالة ذات الرأي في حالة التطبيق في سياق نمط تصميم MVVM.

مقدمة موجزة عن MVVM

تتطلب كتابة كود نظيف وقابل للصيانة استراتيجيات مثل فصل المسؤوليات إلى طبقات مختلفة. هناك العديد من الأنماط المعمارية للبرامج التي تبسط تنظيم الكود إلى طبقات منفصلة مثل MVC و MVP و MVVM وما إلى ذلك. MVVM هو نمط تصميم شائع في كتابة التطبيقات القائمة على واجهة المستخدم بشكل عام.

نموذج عرض عرض النموذج يتعلق بشكل أساسي بهذه الطبقات:

  • عرض View : مسؤول عن العناصر المرئية مثل عناصر واجهة المستخدم على الشاشة
  • النموذج Model : يمكن أن يكون مستودعًا يعتني بإدارة البيانات عبر الخدمات مثل قاعدة البيانات والشبكة وما إلى ذلك
  • ViewModel : يعمل كوسيط للعرض والنمذجة . تتمثل المسؤوليات الرئيسية لهذه الطبقة في الإجراءات المتخذة ومعالجة البيانات وإعادة الحالة الجديدة إلى طبقة العرض.

1. ChangeNotifier

ChangeNotifier هو الصنف المدمج الذي يوفر طريقة notifyListeners () لإبلاغ المستمعين بالتغييرات. يقوم ViewModel إما بتمديد هذه الفئة أو مزجها بحيث يمكنها إخطار تغييرات الخاصية في طبقة العرض. يمكنك الرجوع إلى هذا المثال لفهم كيفية تنفيذه.

هذا حل بسيط للغاية عندما يكون لديك عدد قليل من المستمعين. إضافة أو إزالة مستمع هي عملية O (N) وإرسال الإخطارات هي عملية O (N²).

أيضًا ، عندما يتم استدعاء notifyListeners () ، تتم إعادة بناء جميع أدوات المستمع الخاصة به على الرغم من عدم تغيير الخاصية المستخدمة في عنصر واجهة المستخدم. أحد الحلول لذلك هو استخدام فئة فرعية تسمى ValueNotifier . يمكننا التفاف جميع خصائص ViewModel التي يتم عرضها لطبقة العرض باستخدام ValueNotifier . ولكن هناك حلول أفضل هناك.

2. PropertyChangeNotifier

للتغلب على مشكلة إشعارات تغيير الخاصية الحيادية ، يتم نشر حزمة تسمى property_change_notifier بواسطة Very Good Ventures . توفر هذه الحزمة فئة استبدال منسدلة لـ ChangeNotifier تسمى PropertyChangeNotifier.

عندما تتغير خاصية في ViewModel ، يتم أيضًا تضمين اسم الخاصية في الإعلام. يمكن لأدوات المستمع بعد ذلك اختيار مراقبة خاصية واحدة أو عدة خصائص.

في الواقع ، هذا حل بسيط بدون بذل جهد إضافي لإضافة روابط تفاعلية بين الطبقتين. ولكن بدلاً من إدارة ما تم تغييره يدويًا ، ماذا لو تمكنا من أتمتة تتبع التغييرات ولدينا بعض الميزات الأكثر قوة؟

3. نمط BLoC - ViewModel + Reactivity ️⚡️

يمكننا استخدام فئة السهام الخالصة مثل ViewModel والحفاظ على الخصائص كتدفقات تفاعلية. يمكن لطبقة العرض إضافة إجراء في ViewModel باستخدام StreamController's Sink أو الموضوع من حزمة RxDart . يمكن معالجة هذه الإجراءات وتحويلها إلى عرض تدفقات الخاصية القابلة للتمثيل في ViewModel. من طبقة العرض ، يمكن أن تتفاعل عناصر واجهة المستخدم مع تدفقات ViewModel باستخدام عنصر واجهة المستخدم StreamBuilder .

هذا هو أنقى شكل تفاعلي لإدارة الحالة حيث يمكننا إعادة بناء الحاجيات الضرورية باستخدام دفق خاصية معين في StreamBuilder. إذا كنت ترغب في فهم هذه التقنية عن طريق البرنامج التعليمي ، فإنني أوصي بهذه المقالة . BLoC و ViewModel متطابقان معي ويتم شرح الاختلاف الدقيق بينهما هنا .

لكن اتباع هذا النمط ينطوي على تحديات إضافية. نظرًا لأنه سيكون هناك مغاسل متعددة لقبول إجراءات مختلفة وتدفقات متعددة تتعرض لتفاعل واجهة المستخدم ، فمن السهل جدًا فقدان تتبع تدفق البيانات. لنرى ما فعله مجتمعنا الصاعد لحل هذه المشكلة 😄.

4. حزمة BLoC

تمزج حزمة BLoC بين أيديولوجية نمط BLoC ونمط المخفض . تم تطويره بواسطة Felix Angelov ، وهو شخص يجب متابعته في مجتمع Flutter.


الكتلة (مكون منطق الأعمال) هو مكون يحول تدفق الأحداث الواردة إلى دفق من الدول الصادرة
مكتبة BLoC

الطريقة الوحيدة لإرسال الحدث في الكتلة هي طريقة الإضافة (حدث الحدث). يتم تعيين حدث الإدخال هذا إلى دفق الحالات الجديدة باستخدام طريقة mapEventToState. في أي وقت يمكننا الوصول إلى الدولة باستخدام ملكية الدولة للكتلة. لكل حدث أو ولاية ، يجب أن يكون هناك فصل منفصل يمتد حدثًا أو ولاية.

مع تدفق البيانات أحادي الاتجاه هذا ، قدم Bloc ميزات قوية مثل الانتقالات والمندوبين والمشرف. يمكنك اتباع هذا الدليل التفصيلي لفهم تشريح الكتلة.

BlocBuilder هي الأداة التي يمكنها الاستماع إلى تدفق الدول وإعادة البناء كلما تمت إضافة قيمة جديدة في هذا الدفق. يمكننا تحسين عمليات إعادة البناء باستخدام الوسيطة الوظيفية الإضافية المسماة الشرط أيضًا 🤟.

Bloc هي واحدة من أكثر الأبنية إبداء رأيًا في Flutter. ولكن ماذا لو أردنا المرونة في ViewModel وما زلنا نريد تتبع التغيير الآلي بطريقة أبسط بكثير؟

5. MobX

MobX هي مكتبة إدارة حالة تجعل من السهل توصيل البيانات التفاعلية لتطبيقك بواجهة المستخدم (أو أي مراقب). هذه الأسلاك تلقائية تمامًا وتشعر بأنها طبيعية جدًا.

يدعم MobX تدفق البيانات أحادي الاتجاه. من طبقة العرض ، يتم إرسال الإجراءات إلى ViewModel. تعالج ViewModel الإجراء وتغير حالة خصائصها التي يشار إليها باسم Observables . يتم الكشف عن التغييرات في الخصائص التي يمكن ملاحظتها تلقائيًا بواسطة طبقة العرض ويتم إعادة بناء عناصر واجهة المستخدم فقط إذا لزم الأمر! تكمن قوة عمليات إعادة البناء الانتقائية في ردود الفعل . يتتبع Reaction تلقائيًا الخصائص التي يمكن ملاحظتها المستخدمة فيه ويعيد بناء الأداة فقط إذا تم تغيير إحدى هذه الخصائص في ViewModel. يمكن العثور على الدليل التفصيلي لفهم MobX في سياق Flutter هنا .

في جميع التقنيات المذكورة أعلاه ، ناقشنا آلية الاتصال بين طبقات View و ViewModel. يأتي المزود في الصورة حتى قبل ذلك. المسؤوليات الرئيسية للمزود هي:

  1. أنشئ مثيل ViewModel في مكان ما في شجرة عناصر واجهة المستخدم التي تحتاج عناصر واجهة المستخدم تحتها للوصول (مشترك أو مباشر)
  2. استمر في المثيل ViewModel عبر عمليات إعادة البناء
  3. قم بتوفير مثيل ViewModel من الشجرة عند الحاجة أدناه.

يتم إحتوائه

لقد رأينا بعضًا من العديد من خيارات إدارة الحالة المتاحة لـ Flutter ، والتي ناقشنا فيها:

  • يمكن التحكم في أبسط حالة سريعة الزوال باستخدام أسلوب StatefulWidget و setState ().
  • يمكن أن تساعدنا فئة مدمجة مثل ChangeNotifier من مؤسسة Flutter في إدارة الحالة عندما يكون هناك عدد قليل نسبيًا من المستمعين.
  • قم بتجفيف عمليات إعادة البناء غير الضرورية باستخدام PropertyChangeNotifier.
  • تفيدنا التدفقات التفاعلية من إدارة تغييرات الخاصية يدويًا باستخدام نمط BLoC.
  • يمنحنا نوع نمط المخفض التحكم في الإدخال والإخراج من ViewModel مثل حزمة Bloc.
  • تلقائي بالكامل ، متفاعل من الأرض ؛ يمكن أن تساعدنا MobX في كتابة ViewModels التي تبدو طبيعية وتتتبع التغييرات دون بذل جهد إضافي!

Flutter - State Management إدارة الحالة فلاطر او الجلسات

تعد إدارة الحالة في تطبيق ما من أهم العمليات الضرورية في دورة حياة التطبيق.

دعونا نفكر في تطبيق عربة تسوق بسيط.

  • سيقوم المستخدم بتسجيل الدخول باستخدام بيانات الاعتماد الخاصة به في التطبيق.

  • بمجرد تسجيل المستخدم الدخول ، يجب أن يستمر التطبيق في الاحتفاظ بتفاصيل المستخدم الذي قام بتسجيل الدخول في كل الشاشة.

  • مرة أخرى ، عندما يختار المستخدم منتجًا وحفظه في عربة التسوق ، يجب أن تستمر معلومات سلة التسوق بين الصفحات حتى يقوم المستخدم بسحب عربة التسوق.

  • يُطلق على المستخدم ومعلومات سلة التسوق الخاصة به في أي حالة حالة التطبيق في تلك الحالة.

يمكن تقسيم إدارة الحالة إلى فئتين بناءً على المدة التي تستغرقها الحالة المعينة في التطبيق.

  • سريع الزوال - يستمر لبضع ثوان مثل الحالة الحالية للرسوم المتحركة أو صفحة واحدة مثل التصنيف الحالي للمنتج. يدعم Flutter من خلال StatefulWidget.

  • دولة التطبيق - آخر لتطبيق كامل مثل تسجيل في تفاصيل المستخدم، عربة المعلومات، وما إلى ذلك، الرفرفة تدعم scoped_model من خلال ل.

الملاحة والتوجيه Navigation and Routing 

في أي تطبيق ، يؤدي التنقل من صفحة / شاشة إلى أخرى إلى تحديد تدفق العمل للتطبيق. الطريقة التي يتم بها التعامل مع التنقل في التطبيق تسمى التوجيه. يوفر Flutter فئة توجيه أساسية - MaterialPageRoute وطريقتان - Navigator.push و Navigator.pop ، لتحديد تدفق العمل للتطبيق.

المادة material 

MaterialPageRoute هي أداة تستخدم لعرض واجهة المستخدم الخاصة بها عن طريق استبدال الشاشة بأكملها برسوم متحركة خاصة بالمنصة.

MaterialPageRoute(builder: (context) => Widget())

هنا ، سيقبل الباني وظيفة لبناء محتواها من خلال تزويد السياق الحالي للتطبيق.

التنقل

يتم استخدام Navigation.push للانتقال إلى شاشة جديدة باستخدام عنصر واجهة المستخدم MaterialPageRoute.

Navigator.push( context, MaterialPageRoute(builder: (context) => Widget()), );

Navigation.pop

يتم استخدام Navigation.pop للانتقال إلى الشاشة السابقة.

Navigator.push(context);

دعونا ننشئ تطبيقًا جديدًا لفهم مفهوم التنقل بشكل أفضل.

قم بإنشاء تطبيق Flutter جديد في Android studio ، product_nav_app

  • انسخ مجلد الأصول من product_nav_app إلى product_state_app وأضف الأصول داخل ملف pubspec.yaml.

  • flutter:
       assets: 
       - assets/appimages/floppy.png 
       - assets/appimages/iphone.png 
       - assets/appimages/laptop.png 
       - assets/appimages/pendrive.png 
       - assets/appimages/pixel.png 
       - assets/appimages/tablet.png
  • استبدل رمز بدء التشغيل الافتراضي (main.dart) بكود بدء التشغيل الخاص بنا.

  • import 'package:flutter/material.dart'; 
    void main() => runApp(MyApp()); 
    
    class MyApp extends StatelessWidget { 
       // This widget is the root of your application. 
       @override 
       Widget build(BuildContext context) { 
          return MaterialApp( 
             title: 'Flutter Demo', 
             theme: ThemeData( 
                primarySwatch: Colors.blue, 
             ), 
             home: MyHomePage(
                title: 'Product state demo home page'
             ),
          );
       }
    }
    class MyHomePage extends StatelessWidget {
       MyHomePage({Key key, this.title}) : super(key: key);
       final String title;
       @override 
       Widget build(BuildContext context) {
          return Scaffold(
             appBar: AppBar(
                title: Text(this.title), 
             ), 
             body: Center(
                child: Text('Hello World',)
             ), 
          ); 
       } 
    }
  • دعنا ننشئ فئة المنتج لتنظيم معلومات المنتج.

  • class Product { 
       final String name; 
       final String description; 
       final int price; 
       final String image; 
       Product(this.name, this.description, this.price, this.image); 
    }
  • دعونا نكتب طريقة getProducts في فئة المنتج لإنشاء سجلات المنتجات الوهمية الخاصة بنا.

  • static List<Product> getProducts() {
       List<Product> items = <Product>[]; 
       
       items.add(
          Product( 
             "Pixel", 
             "Pixel is the most feature-full phone ever", 800, 
             "pixel.png"
          )
       ); 
       items.add(
          Product(
             "Laptop", 
             "Laptop is most productive development tool", 
             2000, "
             laptop.png"
          )
       ); 
       items.add(
          Product( 
             "Tablet", 
             "Tablet is the most useful device ever for meeting", 
             1500, 
             "tablet.png"
          )
       ); 
       items.add(
          Product( 
             "Pendrive", 
             "Pendrive is useful storage medium",
             100, 
             "pendrive.png"
          )
       ); 
       items.add(
          Product( 
             "Floppy Drive", 
             "Floppy drive is useful rescue storage medium", 
             20, 
             "floppy.png"
          )
       ); 
       return items; 
    }
    import product.dart in main.dart
    import 'Product.dart';
  • دعونا نقوم بتضمين عنصر واجهة المستخدم الجديد ، RatingBox.

  • class RatingBox extends StatefulWidget {
       @override 
       _RatingBoxState createState() =>_RatingBoxState(); 
    } 
    class _RatingBoxState extends State<RatingBox> {
       int _rating = 0; 
       void _setRatingAsOne() {
          setState(() {
             _rating = 1; 
          }); 
       } 
       void _setRatingAsTwo() {
          setState(() {
             _rating = 2; 
          }); 
       }
       void _setRatingAsThree() {
          setState(() {
             _rating = 3;
          });
       }
       Widget build(BuildContext context) {
          double _size = 20; 
          print(_rating); 
          return Row(
             mainAxisAlignment: MainAxisAlignment.end, 
             crossAxisAlignment: CrossAxisAlignment.end, 
             mainAxisSize: MainAxisSize.max, 
             children: <Widget>[
                Container(
                   padding: EdgeInsets.all(0), 
                   child: IconButton(
                      icon: (
                         _rating >= 1? 
                         Icon( 
                            Icons.star, 
                            size: _size, 
                         ) 
                         : Icon(
                            Icons.star_border, 
                            size: _size, 
                         )
                      ), 
                      color: Colors.red[500], 
                      onPressed: _setRatingAsOne, 
                      iconSize: _size, 
                   ), 
                ), 
                Container(
                   padding: EdgeInsets.all(0), 
                   child: IconButton(
                      icon: (
                         _rating >= 2? 
                         Icon(
                            Icons.star, 
                            size: _size, 
                         ) 
                         : Icon(
                            Icons.star_border, 
                            size: _size, 
                         )
                      ), 
                      color: Colors.red[500], 
                      onPressed: _setRatingAsTwo, 
                      iconSize: _size, 
                   ), 
                ), 
                Container(
                   padding: EdgeInsets.all(0), 
                   child: IconButton(
                      icon: (
                         _rating >= 3 ? 
                         Icon(
                            Icons.star, 
                            size: _size, 
                         ) 
                         : Icon( 
                            Icons.star_border, 
                            size: _size, 
                         )
                      ), 
                      color: Colors.red[500], 
                      onPressed: _setRatingAsThree, 
                      iconSize: _size, 
                   ), 
                ), 
             ], 
          ); 
       }
    }
  • دعنا نعدل عنصر واجهة ProductBox الخاص بنا للعمل مع فئة المنتج الجديدة.

  • class ProductBox extends StatelessWidget {    
       ProductBox({Key key, this.item}) : super(key: key); 
       final Product item; 
       
       Widget build(BuildContext context) {
          return Container(
             padding: EdgeInsets.all(2), 
             height: 140, 
             child: Card( 
                child: Row(
                   mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                   children: <Widget>[ 
                      Image.asset("assets/appimages/" + this.item.image), 
                      Expanded(
                         child: Container(
                            padding: EdgeInsets.all(5), 
                            child: Column(
                               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                               children: <Widget>[
                                  Text(this.item.name, 
                                  style: TextStyle(fontWeight: FontWeight.bold)), 
                                  Text(this.item.description), 
                                  Text("Price: " + this.item.price.toString()), 
                                  RatingBox(), 
                               ], 
                            )
                         )
                      )
                   ]
                ), 
             )
          ); 
       }
    }

دعنا نعيد كتابة عنصر واجهة المستخدم MyHomePage للعمل مع نموذج المنتج ولإدراج جميع المنتجات باستخدام ListView.

class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   final items = Product.getProducts(); 
   
   @override 
   Widget build(BuildContext context) { 
      return Scaffold( appBar: AppBar(title: Text("Product Navigation")), 
      body: ListView.builder( 
         itemCount: items.length, 
         itemBuilder: (context, index) {
            return GestureDetector( 
               child: ProductBox(item: items[index]), 
               onTap: () { 
                  Navigator.push( 
                     context, MaterialPageRoute( 
                        builder: (context) => ProductPage(item: items[index]), 
                     ), 
                  ); 
               }, 
            ); 
         }, 
      )); 
   } 
}

هنا ، استخدمنا MaterialPageRoute للانتقال إلى صفحة تفاصيل المنتج.

  • الآن ، دعنا نضيف ProductPage لإظهار تفاصيل المنتج.

  • class ProductPage extends StatelessWidget { 
       ProductPage({Key key, this.item}) : super(key: key); 
       final Product item; 
       
       @override 
       Widget build(BuildContext context) {
          return Scaffold(
             appBar: AppBar( 
                title: Text(this.item.name), 
             ), 
             body: Center(
                child: Container(
                   padding: EdgeInsets.all(0), 
                   child: Column(
                      mainAxisAlignment: MainAxisAlignment.start, 
                      crossAxisAlignment: CrossAxisAlignment.start, 
                      children: <Widget>[
                         Image.asset("assets/appimages/" + this.item.image), 
                         Expanded(
                            child: Container(
                               padding: EdgeInsets.all(5), 
                               child: Column(
                                  mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                                  children: <Widget>[
                                     Text(
                                        this.item.name, style: TextStyle(
                                           fontWeight: FontWeight.bold
                                        )
                                     ), 
                                     Text(this.item.description), 
                                     Text("Price: " + this.item.price.toString()), 
                                     RatingBox(),
                                  ], 
                               )
                            )
                         )
                      ]
                   ), 
                ), 
             ), 
          ); 
       } 
    }

الكود الكامل للتطبيق كالتالي -

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class Product {
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   Product(this.name, this.description, this.price, this.image); 
   
   static List<Product> getProducts() {
      List<Product> items = <Product>[]; 
      items.add(
         Product(
            "Pixel", 
            "Pixel is the most featureful phone ever", 
            800, 
            "pixel.png"
         )
      );
      items.add(
         Product(
            "Laptop", 
            "Laptop is most productive development tool", 
            2000, 
            "laptop.png"
         )
      ); 
      items.add(
         Product(
            "Tablet", 
            "Tablet is the most useful device ever for meeting", 
            1500, 
            "tablet.png"
         )
      ); 
      items.add(
         Product( 
            "Pendrive", 
            "iPhone is the stylist phone ever", 
            100, 
            "pendrive.png"
         )
      ); 
      items.add(
         Product(
            "Floppy Drive", 
            "iPhone is the stylist phone ever", 
            20, 
            "floppy.png"
         )
      ); 
      items.add(
         Product(
            "iPhone", 
            "iPhone is the stylist phone ever", 
            1000, 
            "iphone.png"
         )
      ); 
      return items; 
   }
}
class MyApp extends StatelessWidget {
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(title: 'Product Navigation demo home page'), 
      ); 
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   final items = Product.getProducts(); 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text("Product Navigation")), 
         body: ListView.builder( 
            itemCount: items.length, 
            itemBuilder: (context, index) { 
               return GestureDetector( 
                  child: ProductBox(item: items[index]), 
                  onTap: () { 
                     Navigator.push( 
                        context, 
                        MaterialPageRoute( 
                           builder: (context) => ProductPage(item: items[index]), 
                        ), 
                     ); 
                  }, 
               ); 
            }, 
         )
      ); 
   }
} 
class ProductPage extends StatelessWidget {
   ProductPage({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(
            title: Text(this.item.name), 
         ), 
         body: Center(
            child: Container( 
               padding: EdgeInsets.all(0), 
               child: Column( 
                  mainAxisAlignment: MainAxisAlignment.start, 
                  crossAxisAlignment: CrossAxisAlignment.start, 
                  children: <Widget>[ 
                     Image.asset("assets/appimages/" + this.item.image), 
                     Expanded( 
                        child: Container( 
                           padding: EdgeInsets.all(5), 
                           child: Column( 
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                              children: <Widget>[ 
                                 Text(this.item.name, style: TextStyle(fontWeight: FontWeight.bold)), 
                                 Text(this.item.description), 
                                 Text("Price: " + this.item.price.toString()), 
                                 RatingBox(), 
                              ], 
                           )
                        )
                     ) 
                  ]
               ), 
            ), 
         ), 
      ); 
   } 
}
class RatingBox extends StatefulWidget { 
   @override 
   _RatingBoxState createState() => _RatingBoxState(); 
} 
class _RatingBoxState extends State<RatingBox> { 
   int _rating = 0;
   void _setRatingAsOne() {
      setState(() {
         _rating = 1; 
      }); 
   }
   void _setRatingAsTwo() {
      setState(() {
         _rating = 2; 
      }); 
   } 
   void _setRatingAsThree() { 
      setState(() {
         _rating = 3; 
      }); 
   }
   Widget build(BuildContext context) {
      double _size = 20; 
      print(_rating); 
      return Row(
         mainAxisAlignment: MainAxisAlignment.end, 
         crossAxisAlignment: CrossAxisAlignment.end, 
         mainAxisSize: MainAxisSize.max, 
         children: <Widget>[
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 1 ? Icon( 
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsOne, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton( 
                  icon: (
                     _rating >= 2 ? 
                     Icon( 
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsTwo, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 3 ? 
                     Icon( 
                        Icons.star, 
                        size: _size, 
                     )
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsThree, 
                  iconSize: _size, 
               ), 
            ), 
         ], 
      ); 
   } 
} 
class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 140, 
         child: Card(
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + this.item.image), 
                  Expanded( 
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column( 
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(this.item.name, style: TextStyle(fontWeight: FontWeight.bold)), Text(this.item.description), 
                              Text("Price: " + this.item.price.toString()), 
                              RatingBox(), 
                           ], 
                        )
                     )
                  ) 
               ]
            ), 
         )
      ); 
   } 
}

قم بتشغيل التطبيق وانقر فوق أي عنصر من عناصر المنتج. ستظهر صفحة التفاصيل ذات الصلة. يمكننا الانتقال إلى الصفحة الرئيسية عن طريق النقر فوق زر الرجوع. يتم عرض صفحة قائمة المنتجات وصفحة تفاصيل المنتج للتطبيق على النحو التالي -

Flutter - State Management إدارة الحالة فلاطر

Flutter - State Management إدارة الحالة فلاطر