أنشئ أول تطبيق Flutter

أنشئ أول تطبيق Flutter:

 

يضم هذا القسم العناوين التالية:

  • الخطوة 1: قم بإنشاء تطبيق Flutter.
  • الخطوة 2: استخدم حزمة (pacakage) خارجية (مكتبة خارجية).
  • الخطوة 3: إضافة Stateful widget
  • الخطوة 4: إنشاء ListView لانهائية قابلة للتمرير (infinite scrolling ListView)
  • تشغيل التطبيق في وضع Profile ووضع Release.

تلميح: يرشدك هذا الدرس إلى كتابة أول تطبيق Flutter على الهاتف المحمول. قد تفضل تجربة كتابة أول تطبيق Flutter على الويب.

يرشدك هذا الدرس إلى كتابة أول تطبيق Flutter، إذا كنت مضطلعا على مفاهيم البرمجة الأساسية مثل المتغيرات والحلقات والشروط، ومعتادا على البرمجة غرضية التوجه (object oreiented programming) فيمكنك إكمال هذا الدرس. إذ لا تحتاج إلى خبرة سابقة في لغة البرمجة Dart ولا في تطوير تطبيقات الجوال أو الويب.

هذا الدرس هو الجزء الأول من برنامج تعليمي مكون من جزأين. يمكنك العثور على الجزء 2 في Google Developers Codelabs (بالإضافة إلى الجزء الأول (يعني هذا الدرس)).

The app that you'll be building

هذا ما سنبنيه في الجزء الأول:

توضح الصورة المتحركة السابقة كيف سيعمل التطبيق في نهاية هذا الدرس.

سنبني تطبيقًا بسيطًا يُنشئ أسماء مقترحة لشركة ناشئة (startup company). يمكن للمستخدم تحديد الأسماء وإلغاء تحديدها، وحفظ أفضلها. يولد الكود شيئا فشيئا (lazily) 10 أسماء في كل مرة. أثناء قيام المستخدم بالتمرير، يتم إنشاء المزيد من الأسماء. لا يوجد حد أقصى لمدى التمرير للقائمة (قائمة لانهائية).

يمكننا أن نلخص ما سنتعلمه في هذا الدرس ضمن النقاط التالية:

  • كيفية كتابة تطبيق Flutter بحيث يبدو تطبيقا أصلياً على أنظمة iOS و Android والويب.
  • البنية الأساسية لتطبيق Flutter.
  • البحث عن الحزم (المكتبات) واستخدامها للاستفادة من الخدمات التي تقدمها.
  • استخدام الـ hot reload لتسريع عملية تطوير التطبيقات.
  • كيفية إنشاء الـ stateful widget.
  • كيفية إنشاء listview لانهائية محملة ببطء (lazily loaded list).

في الجزء الثاني من هذا البرنامج التعليمي، ستضيف التفاعل (interactivity) مع التطبيق وتعديل الـtheme الخاصة بالتطبيق، كما ستضيف القدرة على التنقل من شاشة إلى أخرى (تسمى عملية التنقل هذه ‘route’ في Flutter).

هذا ما ستحتاجه لإتمام هذا الدرس:

لإكمال هذا التمرين ستحتاج الـ Flutter SDK وبيئة التطوير (IDE) التي تفضلها. سنفترض أنك ستستخدم Android Studio، ولكن يمكنك بالتأكيد استخدام المحرر المفضل لديك.

يمكنك استخدام أي من الأجهزة التالية لتجريب التطبيق الذي سنطوره خلال هذا الدرس:

  • أي جهاز محمول يعمل بنظام تشغيل أندرويد أو iOS متصل بالحاسوب وتم ضبطه على الـ developer mode.
  • محاكي iOS ( ولكن سيتطلب هذا تثبيت Xcode tools).
  • محاكي Android (ولكن سيتطلب إعداده في Android Studio).
  • متصفح إنترنت (Chrome مطلوب لتصحيح الأخطاء (debugging)).

الخطوة 1: قم بإنشاء تطبيق Flutter:

أنشئ تطبيق Flutter بسيط باستخدام التعليمات الواردة في صفحة “اختبار القيادة“. ولكن قم بإعطاء المشروع هذا الاسم “startup_namer” بدلا من “flutter_app”.

تلميح: إذا لم تجد “New Flutter Project” كخيار في الـ IDE ، فتأكد من تثبيت المكونات الإضافية (plugins) لـ Flutter و Dart.

بعد إنشاء المشروع، سنقوم بتعديل الملف lib/main.dart

  1. استبدال محتوى الملف lib/main.dart:

قم بحذف محتوى الملف lib/main.dart. واستبدله بالكود التالي الذي يعرض عبارة “Hello world” في منتصف الشاشة.

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

    • في Android Studio and IntelliJ IDEA: إضغط على الكود بالزر اليميني للماوس واختر ” Reformat Code with dartfmt “.
    • في VS Code: إضغط على الكود بالزر اليميني للماوس واختر ” Format Document”.
    • في الـ Terminal: اكتب التعليمة التالية flutter format <filename>.
  1. قم بتشغيل التطبيق: سيظهر ما يلي على الجهاز الذي تستخدمه لتشغيل التطبيق:

Hello world app on Android Hello world app on iOS

تلميح: في المرة الأولى التي تقوم فيها بالتشغيل على جهاز (physical device) ، قد يستغرق التحميل بعض الوقت. بعد ذلك ، يمكنك استخدام إعادة التحميل السريع (hot reload) للحصول على تحديثات سريعة. يؤدي الحفظ أيضًا إلى إعادة تحميل سريع إذا كان التطبيق قيد التشغيل. عند تشغيل تطبيق مباشرة من الـ terminal باستخدام flutter run ، أدخل r لإجراء إعادة التحميل السريع (hot reload).

ملاحظات:

– ينشئ هذا المثال ما يسمى Material app. Material هي visual design language قياسية على الهاتف المحمول والويب. تقدم Flutter مجموعة غنية من عناصر واجهة المستخدم (widgets) المتوافقة مع الـ Material Design.

من الجيد أن تضيف السطر التالي uses-material-design: true إلى ملف pubspec.yaml الموجود في مجلد المشروع تحت العنوان التالي flutter ضمن الملف. سيسمح لك ذلك باستخدام المزيد من ميزات الـ Material Design ،مثل مجموعة الـ Icons المعرفة مسبقًا والمتوافقة مع هذا التصميم.

– نلاحظ ضمن التابع main استخدام الـ arrow (=>) notation. استخدم هذا الكود مع التوابع التي تتكون من سطر واحد.

– يرث التطبيقapp الـ StatelessWidget ، مما يجعل التطبيق نفسه widget. في Flutter ، كل شيء تقريبًا عبارة عن widget ، بما في ذلك العناصر غير المرئية مثل alignment, padding, layout والتي ستدرسها بالتفصيل لاحقا.

– الـ Scaffold widget ( الموجودة ضمن مكتبة Material ) تقدم default app bar ، و body والتي تضم بدورها الـ widget tree الخاصة بالشاشة الرئيسية home screen. يمكن أن تكون الشجرة الفرعية (subtree) لعنصر واجهة المستخدم widget معقدة للغاية.

– تتمثل المهمة الرئيسية للـwidget في توفير تابع يسمى build مسؤول عن تقديم وصف لكيفية ظهور هذه الـ widget على الشاشة.

– يضم الـbody في هذا المثال Center widget والتي بدورها تحتوي Text widget (كإبن وحيد لها). تقوم الـ Center widget بمحاذاة “ابنها” (الـwidget الذي تحتويه) تقوم بمحاذاته إلى وسط الشاشة.

الخطوة 2: استخدم حزمة (pacakage) خارجية (مكتبة خارجية):

في هذه الخطوة ، ستبدأ في استخدام حزمة مفتوحة المصدر (open-source package) تسمى english_words ، والتي تحتوي على بضعة آلاف من الكلمات الإنجليزية الأكثر استخدامًا بالإضافة إلى بعض التوابع المساعدة.

يمكنك العثور على حزمة english_words ، بالإضافة إلى العديد من الحزم مفتوحة المصدر الأخرى ، على pub.dev.

  1. يضم ملف pubspec.yaml كلاً من الـ assets والـ dependencies لتطبيق Flutter.

في pubspec.yaml، أضف سطرا لمكتبة english_words (الإصدار 3.1.5أو أحدث) إلى قائمة الـ dependencies:

  1. أثناء عرض ملف pubspec.yaml في الـAndroid Studio ، انقر على Pub get. يؤدي هذا إلى تحميل الحزمة إلى مشروعك. يجب أن ترى ما يلي في وحدة التحكم:

يؤدي تشغيل الأمر Pub get أيضًا إلى إنشاء ملف pubspec.lock تلقائيًا. يضم هذا الملف قائمة بجميع الحزم التي تم تحميلها إلى المشروع مع أرقام إصداراتها.

  1. انتقل إلى الملف lib/main.dart وقم بعمل استيراد (import) للحزمة الجديدة:

أثناء الكتابة في الـ Android Studio، يمنحك Android Studio اقتراحات لاستيراد المكتبات. ثم يعرض الـ import string باللون الرمادي ، مما يتيح لك معرفة أن المكتبة المستوردة غير مستخدمة (حتى الآن).

  1. استخدم الـ English words package لإنشاء نصٍ ما بدلاً من استخدام السلسلة “Hello World”:

ملاحظة: ” Pascal case” (المعروفة أيضًا باسم ” upper camel case “) ، تعني أن كل كلمة في الـstring ، بما في ذلك الأولى ، تبدأ بحرف كبير. لذا ، فإن “uppercamelcase” تصبح “UpperCamelCase”.

  1. إذا كان التطبيق قيد التشغيل ، فاضغط hot reload لتحديث التطبيق الذي ما يزال قيد التشغيل. في كل مرة تنقر فيها على إعادة التحميل السريع، أو تقوم بعمل حفظ للمشروع ، يجب أن ترى زوجًا مختلفًا من الكلمات ، يتم اختياره عشوائيًا. هذا لأنه يتم إنشاء الكلمات داخل التابع build ، والذي يتم استدعاؤه في كل مرة يتطلب فيها MaterialApp عملية الـ rendering ، أو عند الضغط على زر تبديل النظام الأساسي في الـ Flutter Inspector.

App at completion of second step on Android

App at completion of second step on iOS

هل واجهت أي مشكلة؟

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

الخطوة 3: إضافة Stateful widget:

تتميز الـ Stateless widgets بكونها غير قابلة للتغير (immutable)، وبالتالي فإن جميع الـproperties الخاصة بها لا يمكن أن تتغير إذ يتم سبق الـproperties فيها بالكلمة المحجوزة final مما يعني أنها ثابتة وغير قابلة للتعديل.

وعلى عكس سابقتها فإن الـ Stateful widgets قابلة للتغيرـ حيث يكون لها ما يسمى بالحالة (State) والتي قد تتغير خلال دورة حياة هذه الـwidget.

تحقيق الـ stateful widget برمجياً (Implementing a stateful widget) يتطلب تعريف صفين (2 classes):

  1. StatefulWidget class.
  2. State class.

يقوم الـ StatefulWidget class بإنشاء instance من الـ State class.

إن الـ StatefulWidget class في حد ذاته غير قابل للتغير (immutable)، ويمكن التخلص منه وإعادة إنشائه من جديد. ولكن الـ StatefulWidget class يقوم بإنشاء instance من الـ State class، والتي تكون بدورها قابلة للتغير وتستمر طوال دورة حياة الـ StatefulWidget وتحافظ على (maintain) ما يسمى بـ حالة الـ widget.

في هذه الخطوة ، ستضيف stateful widget تدعى RandomWords ، والتي ستنشئ الـState class الخاص بها الذي يدعى _RandomWordsState. ستستخدم بعد ذلك RandomWords كإبن (child) داخل الـ stateless widget التي تدعى MyApp.

  1. أنشئ الـboilerplate code للـ stateful widget.

في الملف lib/main.dart ، ضع المؤشر في آخر سطر من الملف بعد الكود الموجود مسبقا ضمن الملف، واضغط enter عدة مرات عدة مرات للبدء في سطر جديد. في الـ IDE الخاص بك ، ابدأ في كتابة stful. سيسألك المحرر عما إذا كنت تريد إنشاء Stateful widget. اضغط على enter للقبول. سيظهر الـ boilerplate code للصفوف المطلوبة، وسيتم وضع المؤشر لك لإدخال اسم الـ Stateful widget الخاصة بك.

  1. اكتب RandomWords كاسم للـ widget.

لا تقوم الـ RandomWords بالكثير بخلاف إنشاء الـ State class الخاصة بها.

بمجرد إدخال RandomWords كاسم للـ Stateful widget ، يقوم الـ IDE تلقائيًا بتحديث اسم الـ State class المصاحبة ، وتسميتها _RandomWordsState. بشكل افتراضي ، يكون اسم الـ State classمسبوقًا بـundersocre . يؤدي إضافة undersoce إلى بداية identifier (“معرف” أي اسم متحول أو تابع أو صف (class))إلى جعله “خاص” (private) في لغة Dart . وبالتالي لا يمكن الوصول لهذا المعرف الخاص خارج الملف الموجود فيه، وهي أفضل ممارسة يوصى بها للـ State objects.

يحدِّث الـ IDE أيضًا الـ state class تلقائيًا لترث الـ State<RandomWords> ، مما يشير إلى أنك تستخدم generic State class متخصصة للاستخدام مع RandomWords. معظم الـ app’s logicموجود هنا – فهو يحافظ على الـstate الخاصة بالـwidget RandomWords. يضم الـ_RandomWordsState قائمة أزواج الكلمات (word pairs) التي تم إنشاؤها ، والتي يزداد حجمها إلى ما لا نهاية مع قيام المستخدم بالتمرير ، وفي الجزء الثاني من هذا الدرس ، سيتمكن المستخدم من إضافة أزواج الكلمات إلى المفضلة أو إزالتها من القائمة عن طريق تبديل رمز القلب.

أصبح الكود الخاص بالـwidget كما يلي:

  1. قم بتحديث التابع build في _RandomWordsStateليصبح كما يلي:

  1. قم بإزالة الكود المسؤول عن إنشاء الكلمات من MyApp عن طريق إجراء التغييرات الموضحة كما يلي:

  1. أعد تشغيل التطبيق. يجب أن يعمل التطبيق كما كان من قبل ، ويعرض أزواج الكلمات في كل مرة تقوم فيها بإعادة تحميل التطبيق من خلال hot reload أو القيام بعملية حفظ للملف(save).

تلميح: إذا رأيت تحذيرًا بشأن الـhot reload يقول بأنك قد تحتاج إلى عمل restart للتطبيق ، فقم بعمل restart للتطبيق . قد يكون التحذير خاطئًا ، ولكن عمل restart للتطبيق يضمن أن التغييرات التي أجريتها تتحقق في واجهة التطبيق.

هل واجهت أي مشكلة؟

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

الخطوة 4: إنشاء ListView لانهائية قابلة للتمرير (infinite scrolling ListView):

في هذه الخطوة ، ستقوم بتعديل الكود في الـ _RandomWordsState لإنشاء وعرض list من أزواج الكلمات. أثناء قيام المستخدم بالتمرير ضمن القائمة (المعروضة في الـ ListView widget) يزداد حجم القائمة إلى ما لانهاية (list grows infinitely). يسمح لك الـ ListView’s builder factory constructor بإنشاء list view lazily، عند الطلب.

  1. أضف قائمة تدعى _suggestions إلى الـ RandomWordsState class_ من أجل حفظ ازواج الكلمات المقترحة. وأضف أيضاً متحول يدعى _biggerFont من أجل طعل حجم الـFont أكبر.

بعد ذلك ، ستضيف التابع _buildSuggestions إلى الـ _RandomWordsState. يقوم هذا التابع بإنشاء الـListView التي تعرض أزواج الكلمات المقترحة.

الـ ListView class يوفر builder property ، وهي factory builder و callback function يتم تعريفه كـ anonymous function. يتم تمرير two parameters إلى الـ factory builder الأول BuildContext والثاني الـindex الذي يشير إلى الخانة الحالية ضمن الـ iterator ونرمز لهذا الـ index بـ i والذي يأخذ القيمة الابتدائية 0 ويزيد في كل مرة يتم فيها استدعاء الـ factory builder. يزيد هذا الـ index بمقدار 2 من أجل كل زوج من الكلمات، مرة من أجل الـ listTile (سطر ضمن الـ listView)، ومرة من أجل الـ Divider (خط يفصل بين سطرين ضمن الـlistView). يسمح هذا النموذج للـ suggested list بالاستمرار في النمو بينما يقوم المستخدم بالتمرير.

  1. أضف التابع _buildSuggestions إلى الـ _RandomWordsState:

/*1*/ هنا يتم استدعاء الـ itemBuilder callback مرة واحدة لكل زوج من الكلمات المقترحة ، ويتم وضع كل اقتراح في ListTile (صف ضمن الـ listView). بالنسبة للصفوف الزوجية في الـ listView، يضيف التابع ListTile لزوج الكلمات. بالنسبة للصفوف الفردية ، يضيف التابع Divider (خط يفصل بين سطرين ضمن الـlistView) لفصل الصفوف عن بعضها. لاحظ أنه قد يكون من الصعب رؤية الـDivider على الأجهزة الأصغر حجمًا.

/*2*/ يضيف هذا السطر divider بارتفاع بكسل واحد قبل كل صف في ListView.

/*3*/ يقسم هذا الـexpression (i ~/ 2) الرقم i على 2 ويعيد النتيجة كعدد صحيح integer. على سبيل المثال: إن تقسيم الاعداد التالية 1, 2, 3, 4, 5 يعيد كنتيجة 0, 1, 1, 2, 2 على الترتيب. يحسب هذا الـexpression عدد أزواج الكلمات في الـ listView.

/*4*/ إذا وصلت إلى نهاية أزواج الكلمات المتاحة ، فقم بإنشاء 10 كلمات أخرى وأضفهم إلى قائمة الاقتراحات.

التابع _buildSuggestions يستدعي التابع buildRow_ مرة واحدة لكل زوج من الكلمات. يعرض هذا التابع كل زوج جديد في ListTile ، مما يسمح لك بجعل شكل صفوف الـlistView أكثر جاذبية في الخطوة التالية.

  1. أضف التابع _buildRow إلى :_RandomWordsState

  1. في فئة الـ_RandomWordsState ، قم بتحديث التابع build بحيث يستخدم التابع buildSuggestions ، بدلاً من استدعاء مكتبة إنشاء الكلمات مباشرةً. (تنفذ الـ Scaffold widget التخطيط المرئي (visual layout) الأساسي للـ Material Design.) استبدل الكود الموجود في التابع build بالكود المظلل باللون السماوي:

  1. في الـ MyApp class ، حدِّث التابع build عن طريق تغيير العنوان وتغيير الـ home ليصبح هو الـ RandomWords widget، احذف الأجزاء المظللة بالأحمر واستبدلها بالاجزاء المظللة بالأخضر كما يلي:

  1. أعد تشغيل التطبيق. يجب أن تتمكن من التمرير ضمن القائمة وتشاهد عدد غير منتهي من أزواج الكلمات طالما تقوم بالتمرير ضمنها.

App at completion of fourth step on Android

App at completion of fourth step on iOS

هل واجهت أي مشكلة؟

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

تشغيل التطبيق في وضع Profile ووضع Release:

ملاحظة مهمة: لا تختبر أداء تطبيقك أثناء تمكين وضع التصحيح (debug) ووضع إعادة التحميل السريع (hot reload).

أنت الآن تشغل تطبيقك في وضع التصحيح (debug mode). يقدم الـdebug mode ميزات مفيدة للمطور مثل hot reload أو step debugging ولكنه يقدم هذه الميزات على حساب أداء التطبيق (app performance). فمن المتوقع أثناء تشغيل التطبيق في ال Debug mode أن ترى أداءً بطيئًا ورسومًا متحركة (animations) سيئة.

لمزيد من التفاصيل حول هذا الموضوع، راجع صفحة “أوضاع بناء تطبيق Flutter” (Flutter’s build modes).

ملاحظة مهمة: إذا كنت قلقًا بشأن حجم تطبيقك، فراجع صفحة “قياس حجم التطبيق الخاص بك“.

الخطوات الواجب تنفيذها اللآن:

The app from part 2

تهانينا!

لقد كتبت تطبيق Flutter تفاعلي يعمل على كل من iOS و Android .

في هذا الـcodelab (الدرس المرفق بـ كود)، لقد قمت بما يلي:

  • إنشاء تطبيق Flutter من الألف إلى الياء.
  • كتبت دارت كود.
  • قمت بالاستفادة من مكتبة خارجية (third-party library).
  • استخدم الـ hot reload لتسرع من عملية تطوير التطيبقات.
  • قمت بكتابة stateful widget.
  • قمت بإنشاء قائمة تمرير لا نهائية محملة ببطء.

إذا كنت ترغب في توسيع هذا التطبيق ، فانتقل إلى الجزء الثاني من هذا الدرس على موقع Google Developers Codelabs ، حيث ستضيف الوظائف التالية:

ستضيف التفاعل (interactivity) إلى التطبيق من خلال إضافة أيقونة على شكل قلب يمكنك النقر عليها لتضيف زوجا من الكلمات إلى المفضلة.

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

ستقوم بتعديل الـtheme الخاصة بالتطبيق لتجعله أبيض بالكامل (all-white app).

 

Leave a Comment

Your email address will not be published. Required fields are marked *

en_USEN