استخدام Flutter من Google لتطوير الأجهزة المحمولة عبر الأنظمة الأساسية حقًا
نشرت: 2022-03-10Flutter هو إطار عمل لتطوير الأجهزة المحمولة مفتوح المصدر وعبر الأنظمة الأساسية من Google. يسمح ببناء تطبيقات جميلة وعالية الأداء لنظامي التشغيل iOS و Android من قاعدة رمز واحدة. وهي أيضًا منصة التطوير لنظام التشغيل Fuchsia القادم من Google. بالإضافة إلى ذلك ، تمت هندسته بطريقة يمكن إحضارها إلى منصات أخرى ، عبر تطعيمات محرك Flutter المخصصة.
لماذا تم إنشاء Flutter ولماذا يجب عليك استخدامه
اتبعت مجموعات الأدوات عبر الأنظمة الأساسية تاريخيًا أحد النهجين التاليين:
- يقومون بلف طريقة عرض الويب في تطبيق أصلي وبناء التطبيق كما لو كان موقعًا على شبكة الإنترنت.
- يقومون بلف عناصر تحكم النظام الأساسي الأصلية ويوفرون بعض التجريد عبر الأنظمة الأساسية فوقها.
يتخذ Flutter نهجًا مختلفًا في محاولة لتحسين تطوير الأجهزة المحمولة. يوفر إطار عمل لمطوري تطبيقات العمل ومحركًا بوقت تشغيل محمول لاستضافة التطبيقات. يعتمد إطار العمل على مكتبة رسومات Skia ، مما يوفر عناصر واجهة مستخدم يتم عرضها بالفعل ، بدلاً من كونها مجرد أغلفة على عناصر تحكم أصلية.
يمنح هذا الأسلوب المرونة في إنشاء تطبيق عبر الأنظمة الأساسية بطريقة مخصصة تمامًا مثل خيار غلاف الويب الذي يوفره ، ولكن في نفس الوقت يقدم أداءً سلسًا. وفي الوقت نفسه ، فإن مكتبة الأدوات الثرية التي تأتي مع Flutter ، جنبًا إلى جنب مع مجموعة كبيرة من عناصر واجهة المستخدم مفتوحة المصدر ، تجعلها منصة غنية بالميزات للعمل معها. ببساطة ، Flutter هو أقرب شيء يمتلكه مطورو الأجهزة المحمولة للتطوير عبر الأنظمة الأساسية مع القليل من الحلول الوسط أو بدونها.
سهم
تتم كتابة تطبيقات Flutter بلغة Dart ، وهي لغة برمجة تم تطويرها في الأصل بواسطة Google. Dart هي لغة موجهة للكائنات تدعم كل من التجميع في وقت مبكر وفي الوقت المناسب ، مما يجعلها مناسبة تمامًا لإنشاء تطبيقات أصلية ، مع توفير سير عمل تطوير فعال مع إعادة التحميل السريع لـ Flutter. انتقل Flutter مؤخرًا إلى الإصدار 2.0 من Dart أيضًا.
تقدم لغة Dart العديد من الميزات التي تظهر في لغات أخرى بما في ذلك جمع البيانات المهملة والانتظار غير المتزامن والكتابة القوية والأدوية بالإضافة إلى مكتبة قياسية غنية.
تقدم Dart تقاطعًا بين الميزات التي يجب أن تكون مألوفة للمطورين القادمين من مجموعة متنوعة من اللغات ، مثل C # و JavaScript و F # و Swift و Java. بالإضافة إلى ذلك ، يمكن ترجمة Dart إلى Javascript. بالاقتران مع Flutter ، يسمح هذا بمشاركة التعليمات البرمجية عبر منصات الويب والجوّال.
الجدول الزمني التاريخي للأحداث
- أبريل 2015
تم عرض Flutter (الاسم الرمزي في الأصل Sky) في Dart Developer Summit - تشرين الثاني (نوفمبر) 2015
تمت إعادة تسمية Sky إلى Flutter - فبراير 2018
تم الإعلان عن Flutter beta 1 في Mobile World Congress 2018 - أبريل 2018
تم الإعلان عن Flutter beta 2 - مايو 2018
تم الإعلان عن Flutter beta 3 في مؤتمر Google I / O. تعلن Google أن Flutter جاهز لتطبيقات الإنتاج
مقارنة مع منصات التطوير الأخرى
Apple / Android Native
تقدم التطبيقات الأصلية أقل احتكاك في اعتماد الميزات الجديدة. إنهم يميلون إلى الحصول على تجارب مستخدم أكثر انسجامًا مع النظام الأساسي المحدد نظرًا لأن التطبيقات مبنية باستخدام عناصر تحكم من بائعي الأنظمة الأساسية أنفسهم (Apple أو Google) وغالبًا ما يتبعون إرشادات التصميم التي وضعها هؤلاء البائعون. في معظم الحالات ، ستعمل التطبيقات الأصلية بشكل أفضل من تلك التي تم إنشاؤها باستخدام عروض عبر الأنظمة الأساسية ، على الرغم من أن الاختلاف قد يكون ضئيلًا في كثير من الحالات اعتمادًا على التكنولوجيا الأساسية عبر الأنظمة الأساسية.
تتمثل إحدى الميزات الكبيرة التي تتمتع بها التطبيقات الأصلية في أنها تستطيع اعتماد تقنيات جديدة تمامًا تنشئها Apple و Google في مرحلة تجريبية على الفور إذا رغبت في ذلك ، دون الحاجة إلى انتظار أي تكامل مع جهة خارجية. يتمثل العيب الرئيسي في إنشاء تطبيقات أصلية في عدم وجود إعادة استخدام للكود عبر الأنظمة الأساسية ، مما قد يجعل التطوير مكلفًا إذا كنت تستهدف iOS و Android.
رد فعل أصلي
يسمح React Native بإنشاء التطبيقات الأصلية باستخدام JavaScript. عناصر التحكم الفعلية التي يستخدمها التطبيق هي عناصر تحكم النظام الأساسي الأصلية ، بحيث يشعر المستخدم النهائي بالتطبيق الأصلي. بالنسبة للتطبيقات التي تتطلب تخصيصًا يتجاوز ما يوفره تجريد React Native ، لا تزال هناك حاجة إلى التطوير المحلي. في الحالات التي يكون فيها مقدار التخصيص المطلوب كبيرًا ، تقل فائدة العمل داخل طبقة تجريد React Native إلى درجة يكون فيها تطوير التطبيق محليًا أكثر فائدة في بعض الحالات.
زامارين
عند مناقشة Xamarin ، هناك طريقتان مختلفتان يجب تقييمهما. بالنسبة لنهجهم الأكثر تعددًا للمنصات ، هناك نماذج Xamarin. على الرغم من أن التكنولوجيا مختلفة تمامًا عن React Native ، إلا أنها تقدم من الناحية المفاهيمية نهجًا مشابهًا من حيث أنها تجرد عناصر التحكم الأصلية. وبالمثل ، فإن لها جوانب سلبية مماثلة فيما يتعلق بالتخصيص.
ثانيًا ، هناك العديد من المصطلحات Xamarin-classic. يستخدم هذا النهج منتجات Xamarin's iOS و Android بشكل مستقل لبناء ميزات خاصة بالنظام الأساسي ، تمامًا كما هو الحال عند استخدام Apple / Android الأصلي مباشرةً ، فقط باستخدام C # أو F # في حالة Xamarin. تتمثل فائدة Xamarin في أنه يمكن مشاركة التعليمات البرمجية غير الخاصة بالنظام الأساسي وأشياء مثل الشبكات والوصول إلى البيانات وخدمات الويب وما إلى ذلك.
على عكس هذه البدائل ، يحاول Flutter منح المطورين حلاً أكثر اكتمالاً عبر الأنظمة الأساسية ، مع إعادة استخدام الكود ، والأداء العالي ، وواجهات المستخدم المرنة ، والأدوات الممتازة.
نظرة عامة على تطبيق Flutter
إنشاء التطبيق
بعد تثبيت Flutter ، يكون إنشاء تطبيق باستخدام Flutter أمرًا بسيطًا مثل فتح سطر أوامر وإدخال flutter create [app_name]
، أو تحديد أمر "Flutter: New Project" في VS Code ، أو تحديد "Start a new Flutter Project" في Android استوديو أو IntelliJ.
بغض النظر عما إذا اخترت استخدام IDE أو سطر الأوامر مع المحرر المفضل لديك ، يمنحك قالب تطبيق Flutter الجديد نقطة بداية جيدة للتطبيق.
يجلب التطبيق حزمة flutter
/ material.dart
لتقديم بعض السقالات الأساسية للتطبيق ، مثل شريط العنوان وأيقونات المواد والتسميات. يقوم أيضًا بإعداد عنصر واجهة مستخدم ذو حالة جيدة لشرح كيفية تحديث واجهة المستخدم عندما تتغير حالة التطبيق.
خيارات الأدوات
يوفر Flutter مرونة لا تصدق فيما يتعلق بالأدوات. يمكن تطوير التطبيقات بسهولة من سطر الأوامر مع أي محرر ، كما يمكن أن تكون من IDE مدعوم مثل VS Code أو Android Studio أو IntelliJ. يعتمد النهج المتبع إلى حد كبير على تفضيل المطور.
يقدم Android Studio معظم الميزات ، مثل Flutter Inspector لتحليل أدوات تطبيق قيد التشغيل وكذلك مراقبة أداء التطبيق. كما أنه يوفر العديد من عمليات إعادة البناء الملائمة عند تطوير تسلسل هرمي لعناصر واجهة المستخدم.
يقدم VS Code تجربة تطوير أخف من حيث أنه يميل إلى البدء بشكل أسرع من Android Studio / IntelliJ. يقدم كل IDE مساعدين تحرير مدمجين ، مثل إكمال التعليمات البرمجية ، مما يسمح باستكشاف واجهات برمجة التطبيقات المختلفة بالإضافة إلى دعم تصحيح الأخطاء الجيد.
يتم أيضًا دعم سطر الأوامر جيدًا من خلال أمر flutter
، مما يجعل من السهل إنشاء تطبيق وتحديثه وتشغيله دون أي تبعية أخرى للأدوات بخلاف المحرر.
إعادة تحميل ساخنة
بغض النظر عن الأدوات ، يحافظ Flutter على دعم ممتاز لإعادة التحميل الساخن للتطبيق. يسمح هذا بتعديل تطبيق قيد التشغيل في كثير من الحالات ، مع الحفاظ على الحالة ، دون الحاجة إلى إيقاف التطبيق ، وإعادة البناء وإعادة النشر.
يزيد إعادة التحميل الساخن بشكل كبير من كفاءة التطوير من خلال السماح بالتكرار الأسرع. إنه حقًا يسعد النظام الأساسي للعمل معه.
اختبارات
يتضمن WidgetTester
أداة WidgetTester للتفاعل مع عناصر واجهة المستخدم من الاختبار. يتضمن نموذج التطبيق الجديد اختبارًا نموذجيًا لشرح كيفية استخدامه عند تأليف اختبار ، كما هو موضح أدناه:
// Test included with the new Flutter application template import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:myapp/main.dart'; void main() { testWidgets('Counter increments smoke test', (WidgetTester tester) async { // Build our app and trigger a frame. await tester.pumpWidget(new MyApp()); // Verify that our counter starts at 0. expect(find.text('0'), findsOneWidget); expect(find.text('1'), findsNothing); // Tap the '+' icon and trigger a frame. await tester.tap(find.byIcon(Icons.add)); await tester.pump(); // Verify that our counter has incremented. expect(find.text('0'), findsNothing); expect(find.text('1'), findsOneWidget); }); }
استخدام الحزم والإضافات
Flutter قد بدأ للتو ، ولكن يوجد بالفعل نظام بيئي غني للمطورين: هناك عدد كبير من الحزم والمكونات الإضافية متاحة بالفعل للمطورين.
لإضافة حزمة أو مكون إضافي ، ما عليك سوى تضمين التبعية في ملف pubspec.yaml في الدليل الجذر للتطبيق. ثم قم بتشغيل flutter packages get
إما من سطر الأوامر أو من خلال IDE ، وستجلب أدوات Flutter جميع التبعيات المطلوبة.
على سبيل المثال ، لاستخدام البرنامج المساعد الشهير لمنتقي الصور لـ Flutter ، يحتاج pubspec.yaml فقط إلى إدراجه على أنه تبعية مثل:
dependencies: image_picker: "^0.4.1"
ثم تشغيل flutter packages get
يجلب لك كل ما تحتاجه للاستفادة منه ، وبعد ذلك يمكن استيراده واستخدامه في Dart:
import 'package:image_picker/image_picker.dart';
الحاجيات
كل شيء في Flutter عبارة عن عنصر واجهة مستخدم. يتضمن ذلك عناصر واجهة المستخدم ، مثل ListView
و TextBox
و Image
، بالإضافة إلى أجزاء أخرى من إطار العمل ، بما في ذلك التخطيط والرسوم المتحركة والتعرف على الإيماءات والسمات ، على سبيل المثال لا الحصر.
من خلال جعل كل شيء عنصر واجهة مستخدم ، يمكن تمثيل التطبيق بأكمله ، والذي يعد أيضًا عنصر واجهة مستخدم ، ضمن التسلسل الهرمي لعناصر واجهة المستخدم. إن وجود بنية حيث يكون كل شيء عبارة عن عنصر واجهة مستخدم يوضح من أين تأتي سمات وسلوكيات معينة مطبقة على جزء من التطبيق. هذا يختلف عن معظم أطر التطبيقات الأخرى ، التي تربط الخصائص والسلوك بشكل غير متسق ، وأحيانًا يتم إرفاقها من مكونات أخرى في التسلسل الهرمي وأحيانًا أخرى على عنصر التحكم نفسه.
مثال بسيط لواجهة المستخدم
نقطة الدخول إلى تطبيق Flutter هي الوظيفة الرئيسية. لوضع عنصر واجهة مستخدم لعنصر واجهة مستخدم على الشاشة ، قم باستدعاء main ( main()
runApp()
وقم بتمرير عنصر واجهة المستخدم الذي سيكون بمثابة جذر للتسلسل الهرمي لعنصر واجهة المستخدم.
import 'package:flutter/material.dart'; void main() { runApp( Container(color: Colors.lightBlue) ); }
ينتج عن هذا أداة Container
زرقاء فاتحة تملأ الشاشة:
أدوات عديمة الجنسية مقابل أدوات ذات حالة
تأتي الأدوات في نوعين: عديم الحالة وذات الحالة. لا تغير الأدوات عديمة الحالة محتواها بعد إنشائها وتهيئتها ، بينما تحتفظ عناصر واجهة المستخدم ذات الحالة ببعض الحالة التي يمكن أن تتغير أثناء تشغيل التطبيق ، على سبيل المثال استجابة لتفاعل المستخدم.
في هذا المثال ، يتم رسم عنصر واجهة مستخدم FlatButton
واجهة مستخدم Text
على الشاشة. يبدأ عنصر واجهة Text
ببعض String
الافتراضية لحالته. يؤدي الضغط على الزر إلى تغيير الحالة الذي سيؤدي إلى تحديث أداة Text
، وعرض String
جديدة.
لتغليف عنصر واجهة مستخدم ، قم بإنشاء فئة مشتقة من StatelessWidget
أو StatefulWidget
. على سبيل المثال ، يمكن كتابة Container
ذات اللون الأزرق الفاتح على النحو التالي:
class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Container(color: Colors.lightBlue); } }
سوف يستدعي Flutter طريقة إنشاء الأداة عند إدراجها في شجرة عناصر واجهة المستخدم بحيث يمكن عرض هذا الجزء من واجهة المستخدم.
بالنسبة لعنصر واجهة مستخدم ذي حالة ، اشتُق من StatefulWidget
:
class MyStatefulWidget extends StatefulWidget { MyStatefulWidget(); @override State createState() { return MyWidgetState(); } }
class MyStatefulWidget extends StatefulWidget { MyStatefulWidget(); @override State createState() { return MyWidgetState(); } }
تقوم عناصر واجهة التعامل ذات الحالة بإرجاع فئة State
المسؤولة عن بناء شجرة عنصر واجهة المستخدم لحالة معينة. عندما تتغير الحالة ، يتم إعادة بناء الجزء المرتبط من شجرة عناصر واجهة المستخدم.
في الكود التالي ، تقوم فئة State
بتحديث String
عند النقر فوق الزر:
class MyWidgetState extends State { String text = "some text"; @override Widget build(BuildContext context) { return Container( color: Colors.lightBlue, child: Padding( padding: const EdgeInsets.all(50.0), child: Directionality( textDirection: TextDirection.ltr, child: Column( children: [ FlatButton( child: Text('Set State'), onPressed: () { setState(() { text = "some new text"; }); }, ), Text( text, style: TextStyle(fontSize: 20.0)), ], ) ) ) ); } }
class MyWidgetState extends State { String text = "some text"; @override Widget build(BuildContext context) { return Container( color: Colors.lightBlue, child: Padding( padding: const EdgeInsets.all(50.0), child: Directionality( textDirection: TextDirection.ltr, child: Column( children: [ FlatButton( child: Text('Set State'), onPressed: () { setState(() { text = "some new text"; }); }, ), Text( text, style: TextStyle(fontSize: 20.0)), ], ) ) ) ); } }
يتم تحديث الحالة في دالة تم تمريرها إلى setState()
. عندما يتم استدعاء setState()
، يمكن لهذه الوظيفة تعيين أي حالة داخلية ، مثل السلسلة في هذا المثال. بعد ذلك ، سيتم استدعاء طريقة build
، لتحديث شجرة عنصر واجهة المستخدم ذات الحالة.
لاحظ أيضًا استخدام عنصر واجهة المستخدم Directionality
لتعيين اتجاه النص لأي عناصر واجهة مستخدم في شجرتها الفرعية تتطلب ذلك ، مثل أدوات Text
. الأمثلة هنا هي رمز بناء من البداية ، لذلك Directionality
مطلوبة في مكان ما فوق التسلسل الهرمي لعنصر واجهة المستخدم. ومع ذلك ، فإن استخدام عنصر واجهة المستخدم MaterialApp
، مثل نموذج التطبيق الافتراضي ، يضبط اتجاه النص ضمنيًا.
تخطيط
تعمل وظيفة runApp
على تضخيم الأداة لملء الشاشة افتراضيًا. للتحكم في تخطيط عنصر واجهة المستخدم ، يقدم Flutter مجموعة متنوعة من أدوات التخطيط. هناك عناصر واجهة مستخدم لتنفيذ التخطيطات التي تحاذي عناصر واجهة المستخدم الصغيرة عموديًا أو أفقيًا ، وتوسيع الحاجيات لملء مساحة معينة ، وتقييد الحاجيات إلى منطقة معينة ، وتوسيطها على الشاشة ، والسماح للأدوات أن تتداخل مع بعضها البعض.
هناك عنصران مستخدمان شائعان هما Row
Column
. تقوم هذه الأدوات بتنفيذ تخطيطات لعرض عناصر واجهة المستخدم الفرعية أفقيًا (صف) أو عموديًا (عمود).
يتضمن استخدام أدوات التخطيط هذه ببساطة التفافها حول قائمة من عناصر واجهة المستخدم الفرعية. يتحكم mainAxisAlignment
في كيفية وضع عناصر واجهة المستخدم على طول محور التخطيط ، إما في الوسط أو في البداية أو النهاية أو مع خيارات تباعد متنوعة.
يوضح الكود التالي كيفية محاذاة العديد من عناصر واجهة المستخدم في Row
أو Column
:
class MyStatelessWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Row( //change to Column for vertical layout mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.android, size: 30.0), Icon(Icons.pets, size: 10.0), Icon(Icons.stars, size: 75.0), Icon(Icons.rowing, size: 25.0), ], ); } }
الاستجابة للمس
يتم التعامل مع تفاعل اللمس من خلال الإيماءات المغلفة في فئة GestureDetector
. نظرًا لأنها أيضًا عنصر واجهة مستخدم ، فإن إضافة التعرف على الإيماءات أمر سهل مثل التفاف عناصر واجهة المستخدم الفرعية في GestureDetector
.
على سبيل المثال ، لإضافة معالجة اللمس إلى Icon
، اجعلها تابعة لـ GestureDetector
واضبط معالجات الكاشف للإيماءات المطلوبة لالتقاطها.
class MyStatelessWidget extends StatelessWidget { @override Widget build(BuildContext context) { return GestureDetector( onTap: () => print('you tapped the star'), onDoubleTap: () => print('you double tapped the star'), onLongPress: () => print('you long pressed the star'), child: Icon(Icons.stars, size: 200.0), ); } }
في هذه الحالة ، عند الضغط أو الضغط مرتين أو الضغط لفترة طويلة على الرمز ، تتم طباعة النص المرتبط:
To hot reload your app on the fly, press "r". To restart the app entirely, press "R". An Observatory debugger and profiler on iPhone X is available at: https://127.0.0.1:8100/ For a more detailed help message, press "h". To quit, press "q". flutter: you tapped the star flutter: you double tapped the star flutter: you long pressed the star
بالإضافة إلى إيماءات النقر البسيطة ، هناك مجموعة كبيرة من أدوات التعرف ، لكل شيء بدءًا من التحريك والتحجيم وحتى السحب. هذا يجعل من السهل جدًا إنشاء تطبيقات تفاعلية.
تلوين
يوفر Flutter أيضًا مجموعة متنوعة من عناصر واجهة المستخدم للطلاء بما في ذلك الأدوات التي تعدل العتامة وتعيين مسارات القطع وتطبيق الزخارف. حتى أنه يدعم الرسم المخصص من خلال عنصر واجهة CustomPaint
وفئات CustomPainter
و Canvas
المرتبطة.
أحد الأمثلة على عنصر واجهة الرسم هو DecoratedBox
، والذي يمكنه رسم BoxDecoration
على الشاشة. يوضح المثال التالي كيفية استخدام هذا لملء الشاشة بتعبئة متدرجة:
class MyStatelessWidget extends StatelessWidget { @override Widget build(BuildContext context) { return new DecoratedBox( child: Icon(Icons.stars, size: 200.0), decoration: new BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Colors.red, Colors.blue, Colors.green], tileMode: TileMode.mirror ), ), ); } }
حيوية
يتضمن Flutter فئة AnimationController
التي تتحكم في تشغيل الرسوم المتحركة بمرور الوقت ، بما في ذلك بدء الرسوم المتحركة وإيقافها ، بالإضافة إلى تغيير القيم إلى الرسوم المتحركة. بالإضافة إلى ذلك ، هناك عنصر واجهة مستخدم AnimatedBuilder
يسمح بإنشاء رسم متحرك بالاشتراك مع AnimationController
.
أي عنصر واجهة مستخدم ، مثل النجمة المزخرفة الموضحة سابقًا ، يمكن أن يكون لها خصائص متحركة. على سبيل المثال ، إعادة هيكلة الكود إلى StatefulWidget
، نظرًا لأن الرسوم المتحركة هي تغيير في الحالة ، ويتيح تمرير AnimationController
إلى فئة State
استخدام القيمة المتحركة أثناء إنشاء عنصر واجهة المستخدم.
class StarWidget extends StatefulWidget { @override State createState() { return StarState(); } } class StarState extends State with SingleTickerProviderStateMixin { AnimationController _ac; final double _starSize = 300.0; @override void initState() { super.initState(); _ac = new AnimationController( duration: Duration(milliseconds: 750), vsync: this, ); _ac.forward(); } @override Widget build(BuildContext context) { return new AnimatedBuilder( animation: _ac, builder: (BuildContext context, Widget child) { return DecoratedBox( child: Icon(Icons.stars, size: _ac.value * _starSize), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Colors.red, Colors.blue, Colors.green], tileMode: TileMode.mirror ), ), ); } ); } }
class StarWidget extends StatefulWidget { @override State createState() { return StarState(); } } class StarState extends State with SingleTickerProviderStateMixin { AnimationController _ac; final double _starSize = 300.0; @override void initState() { super.initState(); _ac = new AnimationController( duration: Duration(milliseconds: 750), vsync: this, ); _ac.forward(); } @override Widget build(BuildContext context) { return new AnimatedBuilder( animation: _ac, builder: (BuildContext context, Widget child) { return DecoratedBox( child: Icon(Icons.stars, size: _ac.value * _starSize), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Colors.red, Colors.blue, Colors.green], tileMode: TileMode.mirror ), ), ); } ); } }
class StarWidget extends StatefulWidget { @override State createState() { return StarState(); } } class StarState extends State with SingleTickerProviderStateMixin { AnimationController _ac; final double _starSize = 300.0; @override void initState() { super.initState(); _ac = new AnimationController( duration: Duration(milliseconds: 750), vsync: this, ); _ac.forward(); } @override Widget build(BuildContext context) { return new AnimatedBuilder( animation: _ac, builder: (BuildContext context, Widget child) { return DecoratedBox( child: Icon(Icons.stars, size: _ac.value * _starSize), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Colors.red, Colors.blue, Colors.green], tileMode: TileMode.mirror ), ), ); } ); } }
في هذه الحالة ، يتم استخدام القيمة لتغيير حجم عنصر واجهة المستخدم. يتم استدعاء وظيفة builder
كلما تغيرت القيمة المتحركة ، مما يتسبب في اختلاف حجم النجمة بما يزيد عن 750 مللي ثانية ، مما يؤدي إلى إنشاء مقياس ساري المفعول:
استخدام الميزات الأصلية
قنوات المنصة
من أجل توفير الوصول إلى واجهات برمجة التطبيقات للنظام الأساسي الأصلي على Android و iOS ، يمكن لتطبيق Flutter استخدام قنوات النظام الأساسي. يسمح ذلك لكود Flutter Dart بإرسال رسائل إلى تطبيق iOS أو Android المستضيف. تم إنشاء العديد من المكونات الإضافية مفتوحة المصدر المتوفرة باستخدام المراسلة عبر قنوات النظام الأساسي. لمعرفة كيفية العمل مع قنوات النظام الأساسي ، تتضمن وثائق Flutter مستندًا جيدًا يوضح الوصول إلى واجهات برمجة التطبيقات الأصلية للبطارية.
خاتمة
حتى في الإصدار التجريبي ، يوفر Flutter حلاً رائعًا لإنشاء تطبيقات عبر الأنظمة الأساسية. بفضل الأدوات الممتازة وإعادة التحميل الساخنة ، فإنها توفر تجربة تطوير ممتعة للغاية. تجعل ثروة الحزم مفتوحة المصدر والوثائق الممتازة من السهل البدء بها. بالنظر إلى المستقبل ، سيتمكن مطورو Flutter من استهداف Fuchsia بالإضافة إلى iOS و Android. بالنظر إلى قابلية التوسع في بنية المحرك ، فلن يفاجئني رؤية Flutter Land على مجموعة متنوعة من المنصات الأخرى أيضًا. مع المجتمع المتنامي ، إنه وقت رائع للانضمام إليه.
الخطوات التالية
- تثبيت Flutter
- جولة لغة دارت
- Flutter Codelabs
- دورة Flutter Udacity
- كود مصدر المادة