رفرفة. إيجابيات وسلبيات



بادئ ذي بدء ، دعونا نتحدث قليلاً عن ماهية الرفرفة. هذا إطار عمل لإنشاء تطبيقات الجوال من Google. إنها منصة مشتركة وتتيح لك ترجمة المشروع الذي تم إنشاؤه لثلاثة أنظمة تشغيل:
  • أندرويد
  • iOS
  • الفوشيه

علاوة على ذلك ، بالنسبة إلى أحدث نظام تشغيل - Fuchsia - هذه هي الطريقة الوحيدة لإنشاء تطبيق ما.
تم عرض الرفرفة لفترة طويلة ، منذ عام 2015 ، فقط في إصدارات ألفا وبيتا. تم إصدار النسخة المستقرة الأولى في 4 ديسمبر 2018.


يتم الترويج لـ Flutter بشكل نشط من قِبل Google ، حيث تكتسب شعبية تدريجية ، وعلى الأرجح ، ستستمر في مزاحمة أدوات التطوير عبر المنصات الأخرى المستخدمة حاليًا (React Native، Xamarin) ، خاصةً إذا تم توزيع Fuchsia على نطاق واسع. نظرًا لأن Google تضع نظام التشغيل هذا كبديل لنظام أندرويد ، فإن Flutter عاجلاً أم آجلاً ستحل محل تطوير Android الأصلي. ولذلك ، فإن الآفاق والتنمية النشطة هي المزايا الرئيسية للرفرفة.


+ المنظور والتنمية النشطة


دعونا نرى كيف يعمل.


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


في الوقت نفسه ، في الجزء الأصلي من التطبيق ، يتم إنشاء شاشة واحدة حيث يتم تحميل الجهاز الظاهري Dart ، الذي يقوم بتشغيل Flutter.


لاحظ أن أحد سلبيات Flutter يتبع من هنا:


- حزمة التثبيت النهائي أكبر ، حيث تتم إضافة الجهاز الظاهري Dart إليها.


وبالتالي ، هناك ملفات Flutter وهناك أجهزة افتراضية تتم إضافتها اعتمادًا على ما يجمع - iOS أو Android.


يحتوي الجهاز الظاهري على محرك رسومات خاص به ، حيث يرسم واجهة التطبيق بجميع التحولات بين الشاشات ومربعات الحوار والشظايا ، إلخ. في هذا ، يختلف التطوير في Flutter بشكل كبير عن التطوير مع Xamarin و React Native ، التي تستخدم مكونات Android و iOS الحقيقية. في حالتها ، من المستحيل استخدام مكونات خاصة بالنظام الأساسي (إذا كانت هناك حاجة ، فيجب عليك إنشاء إصدارين من واجهة المستخدم). عند اختيار تصميم باستخدام Flutter ، يكفي التركيز على نظام أساسي واحد (على سبيل المثال ، Android). عند إنشاء مشروع لنظام iOS ، سترى واجهة أندرويد القياسية. ستبدو غريبة بعض الشيء وغير متوقعة ، ولكنها وظيفية للغاية (في وقت لاحق يمكن تحسين الواجهة).


+ محرك رسومات خاص (لا حاجة لإنشاء واجهة بشكل منفصل لنظامي Android و iOS)


الآن عن الانطباعات.


عند نقل العديد من التطبيقات من Android إلى Flutter ، لاحظنا بعض الاختلافات ، والتي يمكن اعتبارها زائدًا وناقصًا.


أول ما يلفت انتباهك هو طريقة لإنشاء شاشات مختلفة بشكل كبير عن تلك المستخدمة على Android و iOS. في Android ، يتم فصل المنطق والواجهة: يتم تعيين المنطق بواسطة الكود ، ويتم تعيين الواجهة حسب التصميم في xml. على الرفرفة ، يتم تعيين كل هذا باستخدام رمز. على الرغم من هنا يتم استخدام نمط خاص للواجهة - يتم إنشاء عناصر واجهة متداخلة داخل بعضها البعض. هذا يشبه إلى حد ما التصميم ، طريقة مماثلة للغاية تعمل في React Native. ومع ذلك ، لا توجد إمكانية للوصول المباشر إلى العناصر. لتغيير شيء ما على الشاشة ، يجب عليك إما تحديث الشاشة بأكملها ، أو استخدام وحدات تحكم خاصة تمت إضافتها إلى الأداة مسبقًا أثناء إنشائها.


- يتم إنشاء واجهة باستخدام رمز ، مما يجعل الخط الفاصل بين المنطق والتصميم أرق بكثير.


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


+ يتم تقسيم الواجهة بسهولة إلى وحدات منفصلة


آخر اثنين من الملاحظات ربما تستحق الدراسة. للقيام بذلك ، سوف نكتب تطبيقًا بسيطًا يوضح بعض ميزات Flutter. سيكون هذا تطبيقًا مع شريط تنقل قياسي وشريط علامات تبويب.


لنجعل ثلاث علامات تبويب:


1) أولاً - مع النص وشرائح التمرير لضبط حجم ولون النص
2) إضافة صورة قابلة للتنزيل إلى الثانية (مع مؤشر التقدم)
3) في المقام الثالث على سبيل المثال قائمة




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

الآن ضع في اعتبارك شفرة المصدر التي تقوم بتنفيذ هذا التصميم:


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: 'Home Page'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } 

جزء الكود هذا قياسي لأي تطبيق Flutter تقريبًا (يتم إنشاؤه مع المشروع).


MyApp هو فئة من التطبيق نفسه ، الذي يصف المعلمات العامة عند إنشاء MaterialApp: اسم التطبيق والخطوط والألوان والأنماط. يشار إلى الشاشة الرئيسية للتطبيق هنا أيضًا (بالنسبة لنا ، هذه هي MyHomePage).


لنلاحظ ملاحظة مهمة: في أدوات Flutter تنقسم إلى نوعين:


1) StatefulWidget
2) StatelessWidget


هناك فصلان مطلوبان لوصف StatefulWidget: فئة عنصر واجهة المستخدم نفسه وفئة حالته (التي سيحدث فيها العمل الرئيسي).


يتم وصف StatelessWidget بواسطة فئة واحدة مع حالة ثابتة ، ولا يمكن تغييره إلا عن طريق إعادة الإنشاء من الأداة الرئيسية. لذلك ، لأغراضنا ، StatefulWidget مطلوب.


الآن خذ بعين الاعتبار _MyHomePageState:


 class _MyHomePageState extends State<MyHomePage> { int _currentIndex = 0; double _size = 14; double _r = 0; double _g = 0; double _b = 0; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: <Widget>[ 

لسهولة الإدراك ، يتم وضع علامة تبويب تحتوي على نص باللون الأحمر ، وعلامة تبويب مع صورة باللون الأخضر ، وعلامة تبويب قائمة باللون الأزرق ، وقائمة التنقل باللون الأصفر. كما ترون ، يتم وصف الواجهة على أنها مجموعة من الأدوات المصغّرة (ومصفوفاتها) المدمجة في بعضها البعض:










الوظائف المستخدمة:
  void _onTapped(int index) { setState(() { _currentIndex = index; }); } void _setTextStyle( {double size = -1, double r = -1, double g = -1, double b = -1}) { setState(() { if (size > 0) { _size = size; } if (r > 0) { _r = r; } if (g > 0) { _g = g; } if (b > 0) { _b = b; } }); } } 

لننظر فيها بمزيد من التفصيل:


onTapped - وظيفة تسمى عند تبديل علامة تبويب في القائمة السفلية. تستدعي وظيفة setState الخاصة ، والتي تتيح لك تحديث الأداة الحالية ببيانات جديدة (وقمنا بتحديث المتغير _currentIndex).


لنرى أين ينطبق:


 body: <Widget>[    ][_currentIndex] 

نحن هنا نتعامل مع صفيف ، حيث يتم استخدام _currentIndex أحد خيارات تخطيط الشاشة ، ويتم استبداله كواحد من علامات التبويب.


بعد ذلك تأتي دالة _setTextStyle. يحتوي على إعلان غير معتاد جدًا على اللغات المشابهة لـ C.


 void _setTextStyle({double size = -1, double r = -1, double g = -1,double b = -1}) 

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


منذ تسمية كل وسيطة ، يمكننا أخذها بترتيب عشوائي. على سبيل المثال:


 _setTextStyle(size: 24, b: 255) 

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


علامة التبويب الأولى:


 class TextWidget extends StatefulWidget { @override _TextWidgetState createState() => _TextWidgetState(); } class _TextWidgetState extends State<TextWidget> { double _size = 14; double _r = 0; double _g = 0; double _b = 0; @override Widget build(BuildContext context) { return Column( children: <Widget>[ Text("Example String", style: TextStyle( fontSize: _size, color: Color.fromRGBO(_r.toInt(), _g.toInt(), _b.toInt(), 1))), Container(constraints: BoxConstraints.expand(height: 32.0)), Slider( label: "${_size.toInt()} sp", value: _size, min: 10, max: 48, divisions: 38, activeColor: Colors.black, inactiveColor: Colors.grey, onChanged: (val) => _setTextStyle(size: val)), Slider( label: _r.toInt().toString(), value: _r, min: 0, max: 255, divisions: 255, activeColor: Colors.red, inactiveColor: Colors.grey, onChanged: (val) => _setTextStyle(r: val), ), Slider( label: _g.toInt().toString(), value: _g, min: 0, max: 255, divisions: 255, activeColor: Colors.green, inactiveColor: Colors.grey, onChanged: (val) => _setTextStyle(g: val), ), Slider( label: _b.toInt().toString(), value: _b, min: 0, max: 255, divisions: 256, activeColor: Colors.blue, inactiveColor: Colors.grey, onChanged: (val) => _setTextStyle(b: val), ), ], ); } } 

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


علامة التبويب الثانية:


 class ImageWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Stack( children: <Widget>[ Center(child: CircularProgressIndicator()), Center( child: FadeInImage.memoryNetwork( placeholder: kTransparentImage, image: 'https://picsum.photos/250?image=9', ), ), ], ); } } 

علامة التبويب الثالثة:


 class ListWidget extends StatelessWidget { @override Widget build(BuildContext context) { return ListView.builder( itemCount: 25, itemBuilder: (BuildContext context, int index) { return Container( child: Text( 'entry $index', style: TextStyle(color: Colors.white), ), margin: EdgeInsets.all(16.0), padding: EdgeInsets.all(16.0), decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.all( Radius.circular(16.0), ), ), ); }, ); } } 

تم تغيير رمز حالة الشاشة الرئيسية:


 class _MyHomePageState extends State<MyHomePage> { int _currentIndex = 0; Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), actions: <Widget>[ IconButton(icon: Icon(Icons.navigate_next), onPressed: next) ], ), body: <Widget>[ TextWidget(), ImageWidget(), ListWidget(), ][_currentIndex], bottomNavigationBar: BottomNavigationBar( currentIndex: _currentIndex, onTap: _onTapped, items: [ BottomNavigationBarItem( icon: new Icon(Icons.text_format), title: new Text('Text'), ), BottomNavigationBarItem( icon: new Icon(Icons.image), title: new Text('Image'), ), BottomNavigationBarItem( icon: Icon(Icons.list), title: Text('ListView'), ) ], )); } 

لذلك ، يمكننا بسهولة تقسيم شاشة واحدة كبيرة إلى شاشة واحدة صغيرة وثلاثة الحاجيات الصغيرة. يمكنك ملاحظة أنه في شاشات Flutter لا تختلف من الناحية النظرية عن الأدوات المصغّرة (بتعبير أدق ، تأخذ الحاجيات وظائف النشاط والشظية والعرض المخصص). هذه الميزة مريحة للغاية عندما يحتاج التطبيق إلى عرض ملء الشاشة لأي عنصر - ولهذا يمكنك استخدام عناصر واجهة المستخدم الخاصة بنا بأقل قدر من التحسين.


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


لا تحتوي عناصر واجهة الاستخدام المعتادة على هذا القيد ، حيث أنه باستخدام طريقة التصميم سيتم تضمينها في الشاشة الرئيسية ، حيث يتوفر Scaffold بالفعل.


لحسن الحظ ، لا تؤثر إضافة السقالة إلى عنصر واجهة مستخدم عادي في أدائها.


يمكنك أيضًا إضافة SafeArea (لتوفير مسافة بادئة لشريط الحالة). يتم الحصول على التحويل البسيط التالي:


من:


 @override Widget build(BuildContext context) { return []; } 

إلى:


 @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: [] ), ); } 

حسنًا ، نعود الآن إلى مناقشة إيجابيات وسلبيات الرفرفة.


تم إصدار الرفرفة مؤخرًا ، لذا فإن الأخطاء شائعة بما فيه الكفاية. هذا ملحوظ بشكل خاص عند تحديث Flutter - بعض المكتبات تبدأ في العمل مع الأخطاء.


- عدم الاستقرار (تم ترك الإصدار التجريبي مؤخرًا)


من الواضح ، عند استخدامك للإطار الجديد ، لديك عدد أقل من المكتبات تحت تصرفك من تطوير Android / iOS الأصلي. ومع ذلك ، لا يزال هناك الكثير من مكتبات Flutter ، ولا تزال تظهر بسرعة كبيرة. على سبيل المثال ، تمت إضافة العديد من المكتبات في النصف الثاني من عام 2018 ، على ما يبدو ، استعدادًا للإصدار الأول الثابت ، وكانت المكتبات الأكثر أهمية (Google Analytics ، Firebase ، Maps ، إلخ) موجودة قبل ذلك.


- مكتبات أقل من التنمية الوطنية
+ أهم المكتبات موجودة بالفعل ، ومكتبات جديدة تخرج باستمرار


حان الوقت للتقييم! دعونا نتذكر جميع إيجابيات وسلبيات ، وترتيب العناصر من أهم إيجابيات إلى أهم السلبيات:


+ عبر منصة
+ المنظور والتنمية النشطة
+ أهم المكتبات موجودة بالفعل ، ومكتبات جديدة تخرج باستمرار
+ محرك الرسومات الخاصة
+ يتم تقسيم الواجهة بسهولة إلى وحدات منفصلة


- حزمة التثبيت النهائي أكبر ، حيث تتم إضافة الجهاز الظاهري Dart إليها
- يتم إنشاء واجهة باستخدام رمز ، مما يجعل الخط الفاصل بين المنطق والتصميم أرق بكثير
- المكتبات (والمعلومات) أقل من التنمية المحلية
- عدم الاستقرار (تم ترك الإصدار التجريبي مؤخرًا)


شكرا لاهتمامكم!

Source: https://habr.com/ru/post/ar441766/


All Articles