كيف فعلت تطبيق سطح المكتب على الرفرفة (+ المكافأة)

في الآونة الأخيرة ، لفتت الأنباء انتباهي إلى أن الإصدار التالي من Flutter (1.9) تم إصداره ، والذي يعد بمختلف الأشياء الجيدة ، بما في ذلك الدعم المبكر لتطبيقات الويب.

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

هذا هو "حلقة واحدة لحكم كل شيء."

بعد أن أدارت رأيي على مدى يومين حول نوع التطبيق الذي يمكنك محاولة تقديمه ، قررت اختيار مهمة باستخدام علامة النجمة - ما الذي نحتاجه في هذه المسارات البالية؟ تأرجح على سطح المكتب وتغلب على الصعوبات البطولية! واستشرافا للمستقبل ، سأقول أنه لا توجد صعوبات تقريبا.

تحت القص - قصة حول كيفية حل مهام برنامج React Native المعتاد باستخدام أدوات Flutter ، بالإضافة إلى الانطباع العام للتكنولوجيا.



بالتفكير في ميزات Flutter التي أود "لمسها" ، قررت أنه في طلبي يجب أن يكون:

  • طلبات إلى API البعيد ؛
  • التحولات بين الشاشات.
  • الرسوم المتحركة الانتقالية
  • مدير الدولة - استرجاع أو شيء مماثل.

لا أعرف كيفية النسخ الخلفي ، لذلك قررت البحث عن واجهة برمجة تطبيقات مفتوحة تابعة لجهة خارجية. نتيجة لذلك ، استقرت على هذا المورد - دورات CBR في XML و JSON ، API . حسنًا ، لقد قررت هنا أخيرًا وظيفة التطبيق: ستكون هناك شاشتان ، على الشاشة الرئيسية قائمة بالعملات بسعر CBR ، عندما تنقر فوق عنصر قائمة ، نفتح شاشة تحتوي على معلومات مفصلة.

تدريب


نظرًا لأن أمر flutter create لا يعرف بعد كيفية إنشاء مشروع لنظام التشغيل Windows / Linux (فقط نظام Mac معتمد حاليًا ، استخدم علامة - --macos لهذا) ، يجب عليك استخدام هذا المستودع ، حيث يوجد مثال مُعد. نقوم باستنساخ المستودع ، ونأخذ example المجلد من هناك ، إذا لزم الأمر ، نعيد تسميته ونواصل العمل فيه.

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

 flutter channel master flutter upgrade 

بالإضافة إلى ذلك ، يجب أن تخبر Flutter أنه يمكنه استخدام النظام الأساسي الخاص بك:

 flutter config --enable-linux-desktop 

أو

 flutter config --enable-macos-desktop 

أو

 flutter config --enable-windows-desktop 

إذا سارت الأمور على ما يرام ، فمن خلال تشغيل أمر flutter doctor يجب أن تشاهد ناتجًا مشابهًا:



لذا ، المشهد جاهز ، الجمهور في القاعة - يمكننا أن نبدأ.

تصميم


أول ما يلفت انتباهك بعد React Native هو عدم وجود لغة ترميز خاصة لا JSX. يفرض عليك الرفرفة أن تكتب منطق الترميز والمنطق في دارت . في البداية ، هذا أمر مزعج: المظهر ليس لديه ما يلفت الانتباه ، الكود يبدو مرهقًا ، وحتى هذه الأقواس موجودة في نهاية المكون!

على سبيل المثال ، مثل:



وهذا ليس الحد! يجدر إزالة واحدة في المكان الخطأ ويضمن لك قضاء وقت ممتع (لا).

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

هذه الميزة هي أن في أنماط Flutter هي نفس المكونات (لتكون أكثر دقة - الحاجيات).

إذا كان في React Native لترتيب ثلاثة أزرار في صف واحد داخل View بحيث تقوم بتوزيع مساحة الحاوية بالتساوي ، يكفي أن flexDirection: 'row' بتعيين flexDirection: 'row' للعرض في الأنماط وإضافة flex: 1 للأزرار في الأنماط ، ثم يحتوي Flutter على مكون منفصل Row لترتيب العناصر في صف واحد منفصل عن "قابلية التوسع" لعنصر على كامل المساحة المتاحة: Expanded .

نتيجة لذلك ، بدلا من

 <View style={{height: 100, width:300, flexDirection: 'row'}}> <Button title='A' style={{flex:1}}> <Button title='B' style={{flex:1}}> <Button title='C' style={{flex:1}}> </View> 

علينا أن نكتب مثل هذا:

 Container( height: 100, width: 300, child: Row( children: <Widget>[ Expanded( child: RaisedButton( onPressed: () {}, child: Text('A'), ), ), Expanded( child: RaisedButton( onPressed: () {}, child: Text('B'), ), ), Expanded( child: RaisedButton( onPressed: () {}, child: Text('C'), ), ), ], ), ) 

أكثر مطول ، أليس كذلك؟

أو ، على سبيل المثال ، تريد إضافة إطار بحواف مستديرة إلى هذه الحاوية. في React Native ، نضيف ببساطة إلى الأنماط:

 borderRadius: 5, borderWidth: 1, borderColor: '#ccc' 

في Flutter ، يتعين علينا إضافة شيء مثل هذا إلى وسيطات الحاوية:

 decoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(5)), border: Border.all(width: 1, color: Color(0xffcccccc)) ), 

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

أولاً ، يجب تقسيم المكونات الكبيرة بالطبع - في عناصر واجهة مستخدم منفصلة أو على الأقل في أساليب فئة عنصر واجهة المستخدم.

ثانياً ، يساعد البرنامج المساعد Flutter في VS Code كثيرًا - في الصورة أعلاه ، يتم توقيع التعليقات على الأقواس بواسطة البرنامج المساعد نفسه (وهي غير قابلة للتشكيل) ، مما يساعد على عدم الخلط بين قوسين. بالإضافة إلى أدوات التنسيق التلقائي - بعد نصف ساعة ، تعتاد على الضغط بشكل دوري على Ctrl+Shift+I لتنسيق الرمز.

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

طلبات API


في React Native ، للحصول على البيانات من بعض واجهة برمجة التطبيقات ، نستخدم عادةً طريقة fetch ، والتي تُرجع Promise لنا.

في الرفرفة ، الوضع مشابه. بعد النظر في الأمثلة الموجودة في الوثائق ، أضفت حزمة http إلى pubspec.yaml ( pubspec.yaml لـ package.json من عالم JS) وكتبت شيئًا مثل هذا:

 Future<http.Response> getAnything() { return http.get(URL); } 

كائن Future مشابه جدًا لمعنى "الوعد" ، لذلك كل شيء شفاف هنا. حسنًا ، لتسلسل / إلغاء تسلسل كائنات json ، يمكنك استخدام مفهوم فئات النماذج باستخدام طرق خاصة من fromJSON / toJSON . يمكنك قراءة المزيد حول هذا في الوثائق .

الانتقال بين الشاشات


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

يعد الانتقال بين الشاشات بسيطًا للغاية: فنحن ننشئ فئة لعنصر واجهة مستخدم الشاشة ، ثم نستخدم فئة Navigator القياسية.

في أبسط الحالات ، قد يبدو مثل هذا:

 RaisedButton( child: Text('Go to Detail'), onPressed: () { Navigator.of(context).push<void>(MaterialPageRoute(builder: (context) => DetailScreen())); }, ) 

إذا كان التطبيق الخاص بك يحتوي على العديد من الشاشات ، فمن المعقول أولاً إعداد قاموس للطرق ، ثم استخدام طريقة pushNamed . مثال صغير من الوثائق:

 class NavigationApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( ... routes: <String, WidgetBuilder>{ '/a': (BuildContext context) => usualNavscreen(), '/b': (BuildContext context) => drawerNavscreen(), } ... ); } } // AnyWidget ... onPressed: () { Navigator.of(context).pushNamed('/a'); }, ... 

بالإضافة إلى ذلك ، يمكنك إعداد رسم متحرك خاص للتبديل بين الشاشات وكتابة شيء مثل هذا:

 Navigator.of(context).push<void>(ScaleRoute(page: DetailScreen())); 

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

إدارة الدولة


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

بالنسبة إلى Flutter ، يوجد مستودع يوضح أمثلة على استخدام أبنية التطبيقات المختلفة - هناك Redux و MVC و MVU ، وحتى تلك التي لم أسمع عنها من قبل.

بعد أن نفشت قليلا في هذه الأمثلة ، قررت التوقف عن Provider .

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

للقيام بذلك ، قم بإضافة حزمة provider إلى pubspec.yaml وإعداد فئة موفر. في حالتي ، يبدو الأمر كما يلي:

 import 'package:flutter/material.dart'; import 'package:rates_app/models/rate.dart'; class RateProvider extends ChangeNotifier { Rate currentrate; void setCurrentRate(Rate rate) { this.currentrate = rate; notifyListeners(); } } 

Rate هنا هو فئة نموذج العملة الخاصة بي (مع name الحقول ، code ، value ، إلخ) ، التيار هو الحقل الذي سيتم تخزين العملة المحددة فيه ، و setCurrentRate هو الطريقة التي يتم من خلالها currentrate القيمة الحالية.

لإرفاق مزودنا بالتطبيق ، نقوم بتغيير رمز فئة التطبيق:

 @override Widget build(BuildContext context) { return ChangeNotifierProvider( builder: (context) => RateProvider(), //   child: MaterialApp( ... ), home: HomeScreen(), ), ); } 

هذا كل شيء الآن ، إذا أردنا حفظ العملة المحددة ، فسنكتب شيئًا من هذا القبيل:

 Provider.of<RateProvider>(context).setCurrentRate(rate); 

وإذا كنا نرغب في الحصول على القيمة المخزنة ، فإن هذا:

 var rate = Provider.of<RateProvider>(context).currentrate; 

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

بناء التطبيق


من الناحية النظرية ، يتم استخدام الأمر flutter build <platform> لإنشاء التطبيق. في الممارسة العملية ، عندما قمت بتنفيذ الأمر flutter build linux ، تلقيت هذه الرسالة:



"لم تؤلم" ، حسب اعتقادي ، شعرت بالرعب من وزن مجلد الإنشاء - 287.5 ميجابايت - وبسبب بساطة روحي ، قمت بحذف هذا المجلد إلى الأبد. كما اتضح - عبثا.

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

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

وبالتالي ، في هذه اللحظة لا يعرف Flutter كيفية تحضير تصميمات الإصدار لسطح المكتب. على أي حال ، لينكس.

بشكل عام ، إذا أغمضت عينيك على هذا الطرح ، فقد تحول التطبيق بالطريقة التي أردتها وأبدو

هكذا


علاوة


نمر إلى المكافأة الموعودة.

حتى في مرحلة كتابة التطبيق ، كنت أرغب في التحقق من صعوبة تحويله إلى منصات أخرى. لنبدأ مع الهاتف الخليوي.

بالتأكيد هناك طريقة أقل وحشية ، لكنني قررت أن أقصر الطرق مباشر. لذلك ، قمت ببساطة بإنشاء مشروع pubspec.yaml جديد ، ونقل ملف pubspec.yaml assets fonts وأدلة lib إليه وأضفت السطر إلى AndroidManifest.xml :

 <uses-permission android:name="android.permission.INTERNET" /> 

بدأ التطبيق بضربة جزاء وحصلت على هذا

صور


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

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

 flutter channel master flutter upgrade flutter config --enable-web cd <into project directory> flutter create . flutter run -d chrome 

ثم قمت بنقل الملفات اللازمة لهذا المشروع بنفس الطريقة الهمجية وتلقيت مثل هذا

يؤدي


الانطباعات العامة


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

بعد أن حصلت على يدي (والأقماع) قليلاً ، بدأت أرى مزايا Flutter على React Native. سأذكر بعض.

اللغة دارت هي لغة مفهومة تماما ولطيفة مع كتابة ثابتة قوية. بعد جافا سكريبت ، كان مثل التنفس من الهواء النقي. توقفت عن الخوف من كسر الشفرة في وقت التشغيل وكان شعورًا ممتعًا. قد يقول شخص ما أن هناك Flow و TypeScript ، لكن الأمر ليس كذلك - في مشاريعنا استخدمنا كلاهما ، وشيء آخر دائماً ما كسر في مكان ما. عندما أكتب في React Native ، لا يسعني إلا أن أشعر أن الكود الخاص بي موجود في الدعائم القابلة للتعديل والتي يمكن أن تنكسر في أي وقت. مع Flutter ، لقد نسيت هذا الشعور ، وإذا كان السعر هو تكرار الكود ، فأنا مستعد لدفعه.

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

البيئة . مع البيئة في React Native ، كل شيء محزن. تتساقط المكونات الإضافية لـ vscode باستمرار ، ويمكن لمصحح الأخطاء أن يلتهم 16 gig من المنطوق و 70 gig من المبادلة ، ويعلق النظام بإحكام (من التجربة الشخصية) ، وسيناريو تصحيح الخطأ الأكثر شيوعًا: "إزالة node_modules ، وتثبيت الحزم مرة أخرى ومحاولة إعادة التشغيل عدة مرات." هذا يساعد عادة ، ولكن bljad! ليس كذلك يجب أن يكون ، ليس كذلك.

بالإضافة إلى ذلك ، سيتعين عليك تشغيل AndroidStudio و Xcode بشكل دوري ، لأن البعض يوضع بهذه الطريقة فقط (في الإنصاف ، مع إصدار RN 0.60 أصبح هذا أفضل).

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

عبر منصة . تعلن React Native مبدأ "تعلم مرة واحدة ، والكتابة في كل مكان" - بمجرد أن تتعلم ، يمكنك الكتابة لمنصات مختلفة. صحيح ، تحت كل منصة سوف تواجه مشاكل خاصة به. ولكن ربما يكون هذا نتيجة عدم نضج React Native - في الوقت الحالي ، أحدث إصدار ثابت هو 0.61. ربما مع إصدار الإصدار 1.0 ، فإن معظم هذه المشاكل سوف تختفي.

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

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

بشكل عام ، تجدر الإشارة إلى أن رفرفة تركت معظمها مشاعر إيجابية ، على الرغم من أن لديه مساحة للنمو. والمشروع التالي سأكون أكثر استعدادًا للبدء فيه ، وليس على React Native.

يمكن العثور على الكود المصدري للمشروع على جيثب .

ملاحظة: أغتنم هذه الفرصة لأهنئ جميع المشاركين في يوم المعلم السابق.

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


All Articles