0% found this document useful (0 votes)
109 views173 pages

Flutter Book 2020 V 01

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
109 views173 pages

Flutter Book 2020 V 01

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 173

‫خطوة بخطوة‬

‫النسخة األولى – طور االنشاء (متجددة)‬

‫نسخة مجانية‬

‫‪ 02‬ابريل ‪0202‬‬

‫تحديث ‪ 26‬ابريل ‪0202‬‬

‫عبدالرخمن عبمان‬
‫أكادبمبة كبابي‬

Kattabi Academy

:‫هذا المقرر مباح ابضا على القبوات البالبة‬

‫قناة التلغرام‬

https://t.me/joinchat/AAAAAFdURPZV5Z-XSaI4Vg

‫الفيسبوك‬

Flutter-103278057864283/?referrer=whatsapp-‫تعلم‬/https://www.facebook.com

‫اليوتيوب‬

https://www.youtube.com/playlist?list=PL3I9kp6OF4yRMJRxAtCbUgnHPAOWzft1t
‫عن االكادبمبة‬

‫اكاديمية كتابي هي اكاديمية افتراضية مفتوحة ومتاحة مجانا للجميع‪ ،‬وللمستخدم مطلق الحرية في االستفادة من الكورسات والدروس‬
‫المقدمة فيها بالوجه الذي يريد‬

‫‪Open access and free‬‬

‫الرؤية ‪vision‬‬

‫ان تكون االكاديمية مرتعا خصبا للباحث عن التميز من خالل توفير احدث الكورسات خاصة للخريج والباحث عن الخبرة العملية‬
‫والعلمية في مجال التعليم والبحوث‪.‬‬

‫الرسالة ‪mission‬‬

‫خدمة الطالب والخريجين من خالل توفير تعليم مفتوح وحر‪ ،‬وخلق جسر بين الخريج وسوق العمل واالسهام في تنمية المجاالت‬
‫البحثية لالكاديميين‬

‫‪Objectives‬‬ ‫األهدا‬

‫‪ .1‬الدراسة في اي وقت ومن اي مكان ‪anytime... anywhere‬‬

‫‪ .0‬سد الفجوة الموجود في كليات الحاسب بالتركيز على الجانب العملي في المقررات التي تقدمها االكاديمية‬

‫‪ .3‬خلق جسر بين الخريج وسوق العمل وذلك بمساعدة الخريج في تعلم ما يحتاجه سوق العمل ‪ -‬االحترا‬

‫‪ .4‬تقديم العلوم الحديثة لطالب البكالوريوس وطالب الدراسات العليا‬

‫‪ .5‬توفير بيئة تعليمية مجانية وحرة من خالل توفير مقررات مفتوحة الوصول باستخدام اليوتيوب ووسائل التواصل االجتماعية‬
‫المختلفة‬

‫موقع اكاديمية كتابي‬

‫على التلغرام‬

‫‪https://t.me/KattabiA‬‬

‫على الفيسبوك‬

‫‪https://www.facebook.com/100264501486891‬‬

‫على اليوتيوب‬

‫‪https://www.youtube.com/c/KattabiAcademy‬‬
‫جدول المحتويات‬

‫‪ .1‬الباب االول‪ :‬ف لتر وادواتها‬


‫‪ .2‬الباب الثاني‪ :‬لغة دارت (‪)Dart‬‬
‫‪ .3‬الباب الثالث‪ : :‬كل شي في ف لتر عبارة عن ويديجت‬
‫‪ .4‬الباب الرابع‪ :‬بالويدجيت االساسية‬
‫‪ .5‬الباب الخامس‪ :‬ويدجيت االدخال‬
‫‪ .6‬الباب السادس‪ :‬ويدجيت سكافولد‬
‫‪ .7‬تخطيط تطبيقك‬
‫‪ .8‬انشاء تطبي تف اعلي‬
‫‪ .9‬تصميم تطبيق من الصفر‬
‫‪ .12‬ويدجيت النموذج (‪)Form‬‬
‫األول‬
‫ف لتر وأدواتها‬
‫املقدمة‬

‫ما هي فلتر‬ ‫‪.1.1‬‬

‫تعترب فلرت اطار معل حيتوي مجموعة من ا ألدوات اليت تسمح لنا بإنشاء تطبيقات تعمل عىل‪:‬‬

‫الاندرويد (‪)Android‬‬ ‫‪‬‬


‫الايفون والايباد (‪)iOS‬‬ ‫‪‬‬
‫ا ألهجزة اللوحية‬ ‫‪‬‬
‫الويب‬ ‫‪‬‬

‫خصائص فلتر‬ ‫‪.1.1‬‬


‫• جمانية‬
‫• مفتوحة املصدر‬
‫• مصمهتا جوجل ومدعومة مهنا‬
‫• يمت تطويرها وصيانهتا من قبل فريق من املطورين يف جوجل ومئات من املسامهني من خارج جوجل من مجيع أأحناء العامل‪.‬‬
‫• يمت اس تخداهما حال ًيا من قبل أالف املطورين يف املؤسسات حول العامل الإنتاج التطبيقات‪.‬‬
‫• رسيع ألنه يمت ترمجته مبارشة من التطبيقات ا ألصلية (‪ )truly native apps‬و ال حيتاج ملرحةل وس يطة مثل ‪ WebViews‬و‪JavaScript‬‬
‫• كتابة الكود مرة واحدة واذلي يرتجم اىل تطبيق ويب ملليارات املتصفحات‪ ،‬وتطبيق ‪ iOS‬ألهجزة الايفون والايباد‪ ،‬وتطبيق اندرويد مجليع‬
‫بيق الهواتف وا ألهجزة اللوحية (‪.)tablets‬‬

‫لماذا فلتر‬ ‫‪.1.1‬‬


‫ملاذا مصمت جوجل فلرت رمغ وجود الكثري من ادوات التطوير املتوفرة يف السوق‪ ،‬حىت جوجل نفسها دلهيا ادوات لتطوير تطبيقات املوبيل مثل اندرويد‬
‫اس تديو ؟‬

‫اكن دافع جوجل من وراء ذكل الايت‪:‬‬

‫اجياد طريقة افضل لبناء تطيقات املوبيل اليت زادت احلاجة إالهيا ً‬
‫كثريا‬ ‫‪‬‬
‫امه ما أأضافته جوجل يف فلرت هو إاماكنية بناء تطبيقات للك الاهجزة باكفة أأنواعها‬ ‫‪‬‬
‫إاجياد طريقة لبناء تطبيقات ‪ iOS‬بصورة أأفضل من ‪ ،Swift‬بناء تطبيقات الاندرويد بصورة أأفضل من ‪ ،Kotlin‬بناء تطبيقات ويب‬ ‫‪‬‬
‫بصورة أأفضل من ‪HTML/JavaScript‬‬
‫مقدرتك للقيام ببناء لك هذه التطبيقات بكود واحد (‪ )one codebase‬س تكون املزية الاقوى يف فلرت‬ ‫‪‬‬
‫االدوات التي نحتاجها للتطوير‪:‬‬ ‫‪.1.1‬‬

‫ادوات التطوير اليت حنتاج لتثبيهتا يف حواس يبنا يك نكون قادرين عىل التطوير بواسطة فلرت يه‬

‫‪1. The Flutter SDK‬‬

‫‪2. IDE‬‬

‫‪3. IDE DevTools‬‬

‫‪4. Emulators/ simulator‬‬

‫‪5. flutter doctor‬‬

‫فلتر ‪SDK‬‬ ‫‪.1.4.1‬‬

‫ما يه ‪ flutter SDK‬؟‬ ‫‪.1.4.1.1‬‬


‫‪ "SDK‬أأدوات تطوير الربجميات" أأو حزمة ‪ SDK‬يه مجموعة من الربامج تُس تخدم لتطوير التطبيقات جلهاز أأو نظام تشغيل معني‪ .‬حتتوي فلرت ‪SDK‬‬
‫عىل مجموعة من ا ألدوات اليت تتيح برجمة تطبيقات الهاتف احملمول ( ‪ ، Android ،iOS‬اإخل‪. ).‬‬

‫ما هو ‪GIT‬؟‬ ‫‪.1.4.1.1‬‬


‫• مت تصممي ‪ Git‬يف البداية وتطويره بواسطة ‪ Linus Torvalds‬لتطوير نواة ‪.Linux‬‬

‫• ‪ Git‬عبارة عن برانمج جماين يمت توزيعه مبوجب رشوط ترخيص ‪GNU General Public version2‬‬

‫نظام التحمك يف الاصدار (‪)VERSION CONTROL SYSTEM‬‬

‫• نظام التحمك يف االإصدار (‪ )VCS‬هو برانمج يساعد مطوري الربامج عىل العمل م ًعا واحلفاظ عىل جسل اكمل لعملهم‪.‬‬

‫فامي ييل وظائف ‪:VCS‬‬

‫‪ ‬يسمح للمطورين بلعمل يف وقت واحد‪.‬‬


‫‪ ‬ال يسمح بستبدال تغيريات بعضهم البعض‪.‬‬
‫‪ ‬حيافظ عىل اترخي لك نسخة‪.‬‬
‫حتميل ‪flutter SDK‬‬ ‫‪.1.4.1.1‬‬
‫أأول ا ألدوات اليت حتتاهجا للتطوير يه ‪ flutter SDK‬ويه تقوم برتمجة وتنفيذ برامج فلرت‬
‫جيب أأن يكون اإصدار ويندوز املس تخدم ‪ 7‬أأو أأعىل وجيب أأن يكون هجازك ونظام تشغيكل ‪ 44‬بت‪ .‬بعد ذكل ميكنك اذلهاب اإىل موقع فلرت وهو‬
‫‪ /https://flutter.dev‬مث مق بتحميل ‪ git‬و فالتر واحفظهام يف هجازك‬

‫خطوات تثبيت ‪GIT‬‬ ‫‪.1.4.1.4‬‬


‫الصور التالية تبني خطوات تثبيت ‪ GIT‬عىل هجاز بنظام تشغيل يوندوز‪:‬‬
‫اختبار ‪GIT‬‬ ‫‪.1.4.1.1‬‬
‫بعد التثبيت ميكنك التاكد من نزول ‪ GIT‬عن طريق الامر التايل‪:‬‬

‫• افتح ‪ windows PowerShell‬مث اكتب الامر التايل‪:‬‬

‫‪git version‬‬
‫تثبيت ‪flutter SDK‬‬ ‫‪.1.4.1.4‬‬
‫الصور التالية توحض خطوات تثبيت ‪:flutter SDK‬‬
4
‫وضع مسار فلرت يف متغريات البيئة (‪)Environment varriables‬‬ ‫‪.1.4.1.7‬‬
‫وضع مسار فلرت يف متغري بيئة ميكنك من الوصول لربامج فلرت من اي ماكن دون احلاجة اىل ادلخول يف مسار فلرت‪.‬‬

‫ميكنك وضع مسار اجملدل ‪ bin‬املوجود داخل جمدل ‪ flutter‬يف متغريات البيئة كام هو موحض يف الصور التالية‪:‬‬
‫• انسخ املسار التايل‬

‫‪C:\flutter\bin‬‬

‫مث افتح متغريات البيئة (‪)Environment varriables‬‬

‫من القامئة ابدا يف ويندوز تكتب ‪ env‬مث اختار ‪edit environment variables‬‬
‫• اضغط عىل زر ‪edit‬‬

‫• اضغط عىل ‪new‬‬

‫• الصق املسار اذلي ثنت بنسخه‬


‫‪C:\flutter\bin‬‬

‫‪• ok‬‬

‫‪• ok‬‬

‫وضع مسار فلرت يف متغريات البيئة (‪ ، )C:\flutter\bin‬ميكنك من تشغيل أأي برانمج يف جمدل ‪ bin‬من أأي دليل‬

‫‪ .1.4.1‬بيئات التطوير المتكاملة ‪IDEs‬‬


‫‪IDE=Integrated Development Environment‬‬

‫تعمل بيئة التطوير املتاكمةل كواهجة برجمة مركزية‪ .‬قد يتضمن ‪ IDE‬انفذة برجمة لكتابة الربانمج و مصحح أأخطاء الإصالح أأخطاء الربانمج ‪ ،‬وحمرر مريئ‬
‫يسمح للمطورين بإنشاء وحترير واهجة املس تخدم الرسومية (‪ )GUI‬للربانمج‪.‬‬
‫تش متل ‪ IDEs‬أأيضً ا عىل مرتمج يس تخدم الإنشاء تطبيقات من ملفات التعلاميت الربجمية املصدر‪.‬‬
‫عادة يمت ربط الـ ‪ IDE‬بملرتمج اخلاص بلغة الربجمة اذلي يريد املطور اس تخداهما مثال اإذا أأردت تصممي برامج بس تخدام جافا جيب أأن تربطه مبرتمج جافا‬
‫وإاذا أأردت تصممي برانمج بواسطة فلرت فيجب أأن تربطه مبرتمج فلرت‬

‫تس تطيع اس تخدام أأي حمرر نصوص لكتابة برامج فلرت لكن هناكل ثالث بيئات تطوير مفضةل ذلكل ‪ ..‬ويه ‪:‬‬

‫‪• VS Code from Microsoft: https://code.visualstudio.com‬‬

‫•‬ ‫‪Android Studiofrom JetBrains: https://developer.android.com/studio‬‬

‫‪• IntelliJ IDEA: www.jetbrains.com/idea/download‬‬


‫تحميل فيجوال استديو كود‬ ‫‪.1.1.1.1‬‬

‫من املوقع مق بختيار النسخة املضغوطة و ‪ 11‬او ‪ 44‬بت ‪ -‬حسب نوع هجازك واحفظها يف هجازك‬

‫اخلطوات التالية تبني كيف حتميل فيجوال اس تديو ‪VS Code from Microsoft‬‬
‫تثبيت فيجوال استديو كود‬ ‫‪.1.1.1.1‬‬

‫يف موقع حتميل فبجوال اس تديو كود اخرتا ملف ‪ zip‬من بني خيارات التزنيل‪.‬هنا لن حتتاج اىل تثبيت وامنا فقط فك امللف املضغوط يف جمدل‬

‫تحميل وتثبيت اندرويد استديو‬ ‫‪.1.1.1.1‬‬

‫يعمتد فلرت عىل التثبيت الاكمل لـ ‪ Android Studio‬لتوفري تبعيات نظام ‪ Android‬ا ألسايس اخلاص به‪ .‬ومع ذكل ‪ ،‬ميكنك كتابة تطبيقات ‪Flutter‬‬
‫يف عدد من احملررات مثل فيجوال اس تديو كود أأو انتلبج ايداي‪.‬‬
‫من موقع اندرويد اس تديو مق بختيار النسخة املناس بة كل مث مق بتحميلها‬
‫تثبيت اندرويد استديو‬ ‫‪.1.1.1.1‬‬
‫‪ .1‬انفر نقرا مزدوجا عىل ملف تثبيت اندرويد‬
‫‪ .1‬اتبع الاختيارات الافرتاضية‬
‫‪ .1‬تأأكد من اتصاكل بالنرت الن هناكل اجزاء وحتديثات يمت تزنيلها من النت‬

‫تحميل إنتلج إيديا‬ ‫‪.1.1.1.1‬‬


‫ادخل عىل موقع انتلج ايداي مث اختار نسخة ‪ community‬ومق بتحميلها يف هجازك‬

‫تثبيت انتلج ايديا‬ ‫‪.1.1.1.1‬‬


‫مق بلنقر املزدوج عىل ملف التثبيت واتبع الاختيارات الافرتاضية حىت يكمتل التثبيت‬

‫الصور التالية توحض خطوات تثبيت انتليج ايداي‬


‫‪Flutter DevTool .1.4.1‬‬
‫حرصاي ؛فهي تس تخدم للتطوير بس تخدام لغات و أأطر أأخرى أأيضً ا‪ .‬ذلا جلعلها تعمل مع فلرت‪ ،‬جيب علينا تثبيت‬
‫بيئات التطوير ليست مصممة لفلرت ً‬
‫‪.Flutter DevTools.‬‬
‫ميكنك تثبيت ‪ DevTools‬يف انتليج ايداي واندرويد اس تديو من خالل الانتقال اإىل ‪ Preferences ➤ Plugins‬من القامئة الرئيس ية‪.‬‬
‫يف ‪ ، VS Code‬انتقل اإىل ‪View ➤ Extensions‬‬
‫تسمى أأدوات ‪ Flutter devtools‬ببساطة "‪ "Flutter‬وس يؤدي البحث اإىل رفعها‪.‬‬
‫يف أأي من النظامني ‪ ،‬اضغط عىل زر ‪Install‬‬
‫بعد تثبيت ‪ IDE‬تثبت فهيا ‪ flutter plugins‬او ما يسمى ‪ .IDE devTool‬هذا يمت من داخل ال ‪ IDE‬وانت متصل بلنت‬

‫هتيئة انتليج ايداي‬

‫• شغل انتليج ايداي بلنقر املزدوج عىل ايقونهتا‬


‫• اخرت‪ theme‬مناسب‬

‫• مث اضغط ‪ X‬الإغالق النافذة‬


plugins ‫• اخرت‬
flutter ‫• اكتب‬
‫• انشئ مرشوع جديد ‪New Project‬‬
Configure-> plugins -> Marketplace ‫• اخرت‬
install ‫ مث اضغط‬flutter ‫• اكتب يف خانة البحث‬
‫‪ ‬اضغط اعادة تشغيل انتلجيداي ‪ Restrat intellij IEDA‬مث اضغط انشاء مرشوع جديد‪. create new project‬‬
‫‪ ‬الان س تظهر فلرت عىل اجلانب ا أليرس‬
‫‪ ‬اخرت فلرت مث اكتب امس املرشوع بعد اختيار موقعه ‪ the location‬مث اضغط انهتاء ‪finish‬‬

‫المحاكيات (‪)Emulators‬‬ ‫‪.1.4.4‬‬


‫جاهزا لرتمجة تطبيقات فلرت‪ .‬ولكن لتشغيلها ‪ ،‬حتتاج اإىل احلصول عىل هجاز لتشغيل التطبيق‬
‫مبجرد تثبيت ‪ IDE‬و ‪ ، DevTools‬س تكون ً‬
‫وعرضه‪.‬‬
‫•احملايك ‪ -‬هجاز افرتايض يعمل عىل المكبيوتر احملمول ‪ /‬سطح املكتب ‪ -‬جيعل من السهل تشغيل التطبيق واختباره وتصحيحه وعرضه‪.‬‬
‫•س تحتاج عىل ا ألرحج اإىل الاختبار عىل لك من ‪ iOS‬و ‪ ، Android‬ذلا س تحتاج اإىل حماكيات للك مهنام‪.‬‬
‫•هناك العديد من احملاكيات املتاحة ‪ ،‬لكننا سنتطرق اىل نوعني هام‬

‫‪ ‬حمايك ‪ iOS‬لـ ‪Xcode‬‬


‫‪ ‬وحمايك‪Android AVD‬‬

‫محاكي‪iOS‬‬
‫•اإذا مل يكن دليك هجاز ‪ ، Mac‬فلن تقوم بتشغيل حمايك ‪ iOS‬أأو حىت الرتمجة اىل نظام ‪ iOS‬لهذا ا ألمر‪.‬‬
‫•لتشغيل حمايك‪ ، iOS‬تفتح ‪ ، Xcode‬مث انتقل اإىل‪Xcode ➤ Open Developer Tool ➤ Simulator.‬‬
‫•سيبد أأ تشغيل احملايك ‪ ،‬ومنه ميكنك حتديد أأي هجاز ‪ iOS‬مبا يف ذكل أأهجزة ‪ iPhone‬و‪. iPad.‬‬

‫محاكي‪Android‬‬
‫•متا ًما مثلام يوجد الكثري من طرازات ‪ ، Android‬فهناك الكثري من حماكيات ‪ ، Android‬ولكن هناك طريقتان شائعتان فقط للتفاعل معهم‬

‫‪Genymotion ‬‬
‫‪AVD Manager ‬‬
‫‪Genymotion‬‬

‫يه رشكة رحبية ‪ ،‬ذلا عندما تزور موقعهم عىل الويب ‪ ،‬فاإهنم سيبذلون قصارى هجدمه لتوجهيك حنو نسخهتم املدفوعة لكننا سرنكز عىل ‪AVD‬‬
‫‪ Manager‬ألنه جماين متا ًما و أأكرث ش يوعًا مع مطوري فلرت‬

‫‪AVD Manager‬‬
‫‪ AVD‬تعين "(‪ ،)Android Virtual Device‬هجاز اندرويد الافرتايض"‪.‬‬

‫ميكنك الوصول اىل ‪ AVD Manager‬من القامئة ‪ Tools‬يف‪Android Studio.‬‬


‫أ‬
‫عند فتحها س تجد قامئة بحملاكياتك املثبتة حال ًيا‪ .‬غالبا ما تكون فارغة يف البداية‪ .‬س يكون دليك القدرة عىل تثبيت واحد أأو أكرث من مئات من احملاكيات‬
‫املتاحة عن طريق الضغط عىل زر‬

‫”‪“ Create Virtual Device...‬‬

‫اضغط عليه وميكنك الاختيار من بني مجيع أأنواع ا ألهجزة أأو اإنشاء هجاز خاص بك‪.‬‬
‫س تحتاج فقط اإىل تثبيت اجلهاز مرة واحدة‪ .‬بعد تثبيته ‪ ،‬ميكن اس تخدام هذا اجلهاز اذلي متت حمااكته من أأي ‪ ، IDE‬سواء اكن ‪IntelliJ / Android‬‬
‫‪ Studio‬أأو ‪ VS Code‬ال حاجة الإعداد منفصل عىل كود‪VS.‬‬

‫تنفيذ البرامج‬
‫لتنفيذ تطبيقاتك البد من اس تخدام موبيل حقيق أأو افرتايض ‪:‬‬
‫الس تخدام موبيل حقيق (‪ )Physical device‬س تقوم بتوصيهل مع حاسوبك عن طريق وصةل ‪ USB‬أأو ميكنك حتميل هجاز موبيل افرتايض‬
‫()‪ )Virtual device (emulator or Simulator‬لتجرب عليه تطبيقاتك‬

‫تثبيت جهاز افتراضي‬


‫يوجد يف اندرويد اس تديو خيار النشاء هجاز افرتايض (تنفذ فيه براجمك) وللقيام بذكل‪:‬‬
‫‪ ‬افتح ‪android studio‬‬
‫‪ ‬اختار ‪Tools‬‬
‫‪ ‬اختار ‪AVD manager‬‬
‫‪ ‬تظهر انفذة هبا خيار ‪Create virtual device‬‬
‫‪ ‬اضغط عىل هذا اخليار فتظهر انفذة ‪Select harware‬‬
‫‪ ‬يف اجلدول اختار اجلهاز اذلي تريد حتت ‪Choose Device defention‬‬
‫‪ ‬مث اضغط ‪Next‬‬
‫يمت حتميل ‪ image‬للجهاز اذلي اخرتت (جيب ان تكون متصل بالنرتنت)‬
‫بعد حتميل ال ‪ image‬سيمت تثبيت اجلهاز وعند اعادة فتح اندرويد اس تديو س تجد اجلهاز الافرتايض ظاهر او ميكنك اتباع اخلطوات التالية‪:‬‬
‫الان اصبح دليك هجاز موبيل افرتايض (نوعه حسب ما اخرتت عند التثبيت) ‪ ،‬ميكنك اس تخدام هذا اجلهاز يف أأي بيئة تطوير من البيئات اليت ذكرانها‬
‫مس بقا يف فيجوال اس تديو كود او انتليج ايداي او ويندوز ِ‬
‫بورشل هذا بالضافة الندرويد اس تديو‪.‬‬
‫لن حتتاج أأي هتيئة او تثبيت فمبجرد حتميل اجلهاز الافرتايض يف اندرويد اس تديو س يظهر كل يف بيئات التطوير الاخرى‬
‫الان اصبحنا جاهزبن لكتابة وتنفيذ أأول برانمج فلرت‬

‫‪ .1.4.1‬دكتور فلتر (‪)flutter doctor‬‬


‫س تقوم بتشغيل دكتور فلرت من سطر ا ألوامر‪ .‬ليتحقق من مجيع ا ألدوات املوجودة يف سلسةل أأدواتك ويبلغ عن أأي مشالك يواهجها‪.‬‬
‫بعد الانهتاء من تثبيت لك الادوات اليت حنتاهجا للتطوير ميكنك التأأكد من ان لك شئ عىل ما يرام عن طريق تنفيذ الامر‬

‫‪flutter doctor‬‬

‫وهو يقوم بلتحقق من وجود لك الادوات اليت حتتاهجا ويظهر كل تقرير بذكل وميكنك تشغيل هذا الامر من ‪Windows PowerShell‬‬

‫اإذا ظهر اخلطأأ "ال توجد أأهجزة متاحة" فميكن كتابة ا ألمر التايل‬
‫‪flutter devices‬‬
‫س تظهر لك ا ألهجزة املوجودة‬

‫ملحوظة‪:‬‬
‫يعد اخلطأأ "ال توجد أأهجزة متاحة" أأ ًمرا شائ ًعا ‪ ،‬وميكنك عاد ًة جتاهل هذا اخلطأأ‪ .‬هذا يعين أأنه يف تكل اللحظة مل يكن هناك حماكيات قيد التشغيل‬
‫ملعرفة احملاكيات اليت مت تثبيهتا اكتب ا ألمر‬
‫‪flutter emulators‬‬
‫س تظهر كل لك احملاكيات اليت مت تثبيهتا يف اجلهاز ‪ ،‬وميكنك تشغيل أأي مهنا بكتابة ا ألمر التايل (اذلي حيتوي عىل امس احملايك )‬
‫‪]flutter emulators -- launch [emulator name‬‬
‫وميكنك احلصول عىل تقرير مفصل عن طريق ا ألمر‬
‫‪flutter doctor –v‬‬

‫ميكن تشغيل دكتور فلرت من داخل اي من بيئات التطوير التالية‪:‬‬


‫‪VS code ‬‬
‫‪Android studio ‬‬
‫‪Intellij IDEA ‬‬
‫انشاء اول مشروع‬ ‫‪.1.1‬‬

‫حروف صغرية فقط للتسمية‬

‫جيب عند اإنشاء مرشوعك او تطبيقك ان تكتب الامس بحلروف الصغرية فقط وميكن اس تخدام الاندراسكور للفصل بني اللكامت‪ ،‬مثال‬
‫‪hello_world‬‬

‫اذا ادخلت حرف كبري س تظهر كل رساةل اكلتايل‪:‬‬

‫اإنشاء تطبيق جديد وتنفيذه من خالل ويندوز ِ‬


‫بورشل‪:‬‬

‫‪ .1‬افتح ويندوز ِ‬
‫بورشل‬
‫‪ .1‬شغل احملايك (الاميوليرت)‬
‫‪ .1‬النشاء تطببق جديد (مثال ‪ )my_first_app‬اكتب الامر‬
‫‪flutter create my_first_app‬‬
‫سيمت انشاء الكثري من امللفات واجملدلات اليت تعترب جزء من التطبيق (جيب ان تكون متصل بلنت)‬
‫‪ .4‬عندما يكمتل انشاء التطبيق بنجاح س تظهر رساةل ‪All done‬‬
‫‪ .1‬الان ميكنك تنفيذ التطبيق بدلخول يف جمدل التطبيق (‪ )cd my_first_app‬مث كتابة الامر‪:‬‬
‫‪flutter run‬‬
‫مكوانت التطبيق‬

‫التطبيق اذلي مت اإنشاؤه بس تخدام ‪ flutter create‬يتكون من عدد من اجملدلات وامللفات ميكنك مشاهدة هذه امللفات من خالل ادلخول عىل جمدل‬
‫التطبيق بالمر‪:‬‬
‫‪cd my_app01‬‬
‫مث عرض امللفات بالمر‪:‬‬
‫‪dir‬‬
‫ما هيمنا حاليا يف لك هذه امللفات واجملدلات جمدل واحد هو ‪ lib‬اذلي حيتوي ‪main.dart‬‬

‫انشاء مرشوع جديد وتنفيذه بس تخدام فيجوال اس تديو كود‬

‫اتبع اخلطوات التالية‪:‬‬


‫‪ .1‬افتح فيجوال اس تديو كود‬
‫أ‬
‫‪ .1‬اتكد من تثبيت فلرت من خالل زر ‪ Extensions‬أو بلضغط عىل ‪Ctrl+Shift+X‬‬
‫‪ .1‬من القامئة ‪ View‬اختار ‪ Command Palette‬أأو اضغط عىل ‪Ctrl+Shift+P‬‬
‫‪ .4‬اكتب الامر ‪ Flutter: New Project‬واضغط ‪Enter‬‬
‫‪ .1‬اكتب امس املرشوع مثال ‪my_1st_vsc_app‬ا‬
‫‪ .4‬اختار او مق بنشاء جمدل للمرشوع وانتظر حىت يمت انشاء املرشوع‬
‫‪ .7‬شغل احملايك (‪)emulator‬‬
‫أ‬
‫‪ .8‬نفذ الربانمج من القامئة ‪ Debug‬اخرت ‪ Start Debugging‬او اضغط ‪ F5‬أو من‪ command Palette‬اكتب الامر ‪flutter run‬‬
‫انشاء وتنفيذ تطبيق فلرت بس تخدام اندرويد اس تديو‬

‫اتبع اخلطوات التالية‪:‬‬


‫‪ .1‬افتح اندرويد اس تديو‬
‫‪ .1‬يف ‪ config‬اخرت ‪ plugins‬لتثبيت فلرت اذا مل تكن مثبتة‬
‫‪ .1‬اخرت ‪ start a new flutter project/Create New Project‬من شاشة الرتحيب او ‪ File > New > Project‬من داخل الربانمج‬
‫‪ .4‬اخرت ‪ Flutter‬مث ‪Next‬‬
‫‪ -1‬اكتب امس مشوعك ‪ ،‬مثال ‪flutter_app01‬‬
‫‪ -4‬اخرت مماكن ختزين املرشوع مث اضغط ‪Finish‬‬
‫‪ .7‬شغل احملايك (‪ )emulator‬من ‪ tools‬مث ‪AVD manager‬‬
‫‪ .8‬من القامئة ‪ Run‬اخرت ‪Run main.dart‬‬

‫انشاء وتنفيذ تطبيق فلرت بس تخدام انتليج ايداي‬

‫اتبع اخلطوات التالية‪:‬‬


‫‪ .1‬افتح انتليج ايداي‬
‫‪ .1‬اخرت ‪create new project‬‬
‫‪ .1‬اخرت ‪ flutter‬وحدد مسار ‪ flutter‬يف هجازك‬
‫‪ .4‬اكتب امس املرشوع واضغط ‪finish‬‬
‫‪ .1‬سيمت اإنشاء املرشوع‬
‫‪ .4‬اخرت الاميوليرت‬
‫‪ .7‬نفذ الربانمج بختيار ‪ run main.dart‬من القامئة ‪Run‬‬
)main.dart( ‫امللف الرئييس يف املرشوع‬
‫ وهو امللف الرئييس اذلي يمت‬lib ‫ اذلي يوجد يف اجملدل‬main.dart ‫ مهنا امللف‬،‫ س تجد الكثري من اجملدلات وامللفات‬،‫عندما يمت انشاء مرشوع فلرت‬
.‫تنفيذه‬
.‫ ويف ا ألسفل زر عامئ عند ما تضغط عليه يزيد العداد اذلي يظهر يف التطبيق‬Hello World ‫املرشوع عند تنفيذه يظهر عبارة‬

‫المراجع‬

1. Beginning App Development with Flutter, Create Cross-Platform Mobile Apps, Rap Payne, 2019
2. https://flutter.dev/docs/get-started/install
3. 12 August 2018, Git An introduction to Git: what it is, and how to use it, Aditya Sridhar,
https://www.freecodecamp.org/news/what-is-git-and-how-to-use-it-c341b049ae61/

4. --fast-version-control, https://git-scm.com/book/en/v2/Getting-Started-What-is-Git%3F

‫الرجوع جلدول احملتوايت‬


‫الباب الثاني‬

‫مقدمة عن لغة دارت ‪Dart‬‬


‫‪ .1.2‬السلوك والتمثيل‬
‫البنامج مثا قراءة وكتابة ومعالجة البيانات‬
‫‪ .1‬السلوك (‪ :)behaviour‬وهو ما يفعله ر‬

‫وعبها‬
‫البنامج مثل االزرار ومربعات النص وااليقونات ر‬
‫‪ .2‬التمثيل (‪ :)presentation‬وهو شكل ر‬

‫معظم أطر العمل (‪ )frameworks‬السابقة تستخدم لكل جزء من أجزاءها لغة مختلفة‪ ،‬مثال‬
‫‪ Xamarin‬يستخدم للسلوك لغة ‪ C#‬وللتمثيل ‪( XAML‬الجدول ادناه)‬

‫رن‬
‫لالثني معا (للسلوك وللتمثيل)‬ ‫اما ر‬
‫فلب فتستخدم نفس اللغة (‪)Dart‬‬

‫ه دارت (‪)Dart‬‬
‫‪ .1.1‬ما ي‬
‫ر‬ ‫ن‬
‫وه دارت‪.‬‬
‫البمجة المستخدمة ‪ ،‬ي‬
‫قبل أن نتعمق يف تطوير تطبيقات فلب ‪ ،‬تحتاج إىل فهم لغة ر‬

‫الكببة مثل (‪) Google AdWords‬‬ ‫ً‬


‫داخليا مع بعض منتجاتها ر‬ ‫أنشأت قوقل لغة دارت وتستخدمها‬
‫ن‬
‫تفاعل‪.‬‬
‫ي‬ ‫ثم أتاحت قوقل دارت للجمهور يف عام ‪ ، 2111‬وتستخدم لبناء كل ما هو‬
‫ن‬
‫س يف بناء الجمل‬‫ه لغة برمجة كائنية التوجه )‪ ، (OOP‬ولها نمط قائم عل الفئة ‪ ،‬وتشبه لغة ي‬
‫دارت ي‬
‫إذا كنت عل دراية باي لغة من اللغات التالية‪:‬‬

‫‪C#‬‬

‫‪C ++‬‬

‫‪Swift‬‬
‫‪Kotlin‬‬

‫‪Java / JavaScript‬‬
‫ن‬
‫فستتمكن من البدء يف التطوير بواسطة دارت برسعة ‪.‬‬
‫ً‬
‫نسبيا ‪.‬‬ ‫تعتب دارت لغة بسيطة للتعلم ‪ ،‬ويمكنك البدء برسعة‬
‫ر‬

‫بعض مزايا استخدام دارت‬ ‫‪.1.2‬‬


‫دارت بترجم الى كود أصلي ‪ ،‬مما يجعل تطبيق فلتر الخاص بك سريعًا‪ .‬بعبارة أخرى ‪ ،‬ليس هناك وسيط لتفسير‬ ‫‪‬‬
‫لغة إلى أخرى ‪ ،‬وال توجد جسور‪.‬‬
‫ايضا تستخدم فلتر ترجمة)‪ just-in-time (JIT‬عند تصحيح أخطاء تطبيقك عن طريق تشغيله في المحاكي‪.‬‬ ‫‪‬‬
‫بما ان فلتر تستخدم دارت ‪ ،‬معظم كود واجهة المستخدم )‪ (UI‬مكتوب بلغة دارت ‪ ،‬مما يلغي الحاجة إلى استخدام‬ ‫‪‬‬
‫لغات منفصلة (‪ )markup, visual designer‬إلنشاء واجهة المستخدم ‪.‬‬
‫إطارا في الثانية‬
‫ً‬ ‫إطارا في الثانية )‪ (fps‬و ‪102‬‬
‫ً‬ ‫‪ ‬يعرض فلتر (‪ )Flutter rendering runs at‬بسرعة ‪02‬‬
‫(لألجهزة بسرعة ‪ 102‬هرتز)‪ .‬كلما زاد عدد اإلطارات في الثانية ‪ ،‬كان التطبيق أكثر سالسة‪.‬‬

‫‪.1.2‬التعليقات (‪)Comments‬‬
‫التعليق يضاف للغة البمجة ليساعد نف التوثيق وفهم الكود فقط لذلك نجد أن ر‬
‫المبجم عندما يجد‬ ‫ي‬ ‫ر‬
‫أي تعليق فإنه بيتجاوزه‬

‫التعليق نوعي‬
‫‪ .1‬تعليق عل سطر واحد يبدأ بالعالمة ‪ //‬ر‬
‫حت نهاية السطر‬
‫ن‬
‫وينته بالعالمة *‪/‬‬
‫ي‬ ‫‪ .2‬أو يف عدة سطور يبدأ بالعالمة ‪*/‬‬

‫ن‬
‫مثال لتعليق يف سطر الواحد‬

‫‪//Define the user's age.‬‬

‫‪int age = 25; // The age 25‬‬

‫ن‬
‫مثال لتعليق يف عدة سطور‬

‫‪/* This‬‬

‫‪multi‬‬
‫‪Line‬‬

‫‪Comment */‬‬

‫رن‬
‫للنوعي هما‪:‬‬ ‫ر‬
‫توثيق (‪)documentation comment‬‬ ‫أيضا هنالك تعليق‬
‫ي‬
‫‪/// one line documentation comment‬‬

‫أو‬

‫‪/** multi line‬‬

‫‪documentation‬‬

‫‪comment‬‬

‫‪*/‬‬
‫ر ن‬
‫توثيق يف سطر واحد‪:‬‬
‫ي‬ ‫مثال لتعليق‬

‫‪/// This is a documentation comment.‬‬


‫ر ن‬
‫توثيق يف عدة سطور‪:‬‬
‫ي‬ ‫مثال لتعليق‬

‫‪/** This, too, is a‬‬

‫‪documentation comment‬‬

‫‪*/‬‬

‫المتغيات‬ ‫‪.1.2‬‬
‫ن‬
‫المتغبات باستخدام كلمة ‪ var‬أو باستخدام النوع أو عن طريق كلمة‬
‫ر‬ ‫يف لغة ‪ Dart‬يتم اإلعالن عن‬
‫‪ dynamic‬أو باستخدام ‪object‬‬

‫مثال‬

‫";‪var x = "test 1‬‬

‫أو‬
‫";‪String y = "test 2‬‬

‫أو‬

‫";‪dynamic z = "test 3‬‬

‫أو‬

‫";‪Object w = "test 4‬‬


‫ن‬
‫التاىل‬
‫يتغب نوعه‪ ،‬فإذا كتبت مؤخرا يف الكود أمر مثل ي‬
‫المتغب قد ر‬
‫ر‬ ‫يخب ‪ Dart‬ان هذا‬
‫النوع ‪ dynamic‬ر‬

‫;‪x = 42‬‬

‫فلن تحصل مشكلة‬

‫‪ .1.2‬الثوابت والقيم النهائية ‪Constants and Final Values‬‬


‫المتغب بأنه ثابت أي ذو قيمة نهائية ثابتة‪:‬‬
‫ر‬ ‫الكلمات المفتاحية ‪ const‬و ‪ final‬كالهما ّ‬
‫يعرف‬

‫; "‪const x = "test‬‬
‫ن‬
‫يمكن وضع النوع يف التعريف‪:‬‬

‫; "‪const String x = "test‬‬

‫ويمكنك استخدام كلمة ‪ final‬بدال من ‪:const‬‬

‫; "‪final x = "test‬‬
‫ن‬ ‫ر‬ ‫ن‬
‫يعت أن قيمتها ال‬
‫متغبات ‪ const‬ثابتة يف وقت البجمة (‪ ،)compile time‬مما ي‬
‫الفرق بينهما هو أن ر‬
‫ن‬
‫سء يف وقت التشغيل (‪.)run time‬‬ ‫يمكن أن تعتمد عل أي ي‬
‫لذلك ‪ ،‬إذا حاولت‪:‬‬

‫; ()‪const x = DateTime.now‬‬

‫فهذا لن ينجح‪.‬‬

‫التاىل ينجح‪:‬‬
‫ولكن األمر ي‬
‫; ()‪final x = DateTime.now‬‬
‫ن‬ ‫تعيي قيمة ل ‪ final‬مرة نف وقت ر‬
‫يعت أنه يمكنك ر ن‬ ‫ن‬
‫البجمة‪ ،‬وبعدها يمكنك القيام بذلك يف وقت‬ ‫ي‬ ‫مما ي‬
‫ن‬
‫تعت أنه يمكنك تعيينها مرة واحدة فقط ‪ ،‬حيث يجب أن تكون قيمتها‬ ‫التشغيل ‪ ،‬نف ر ن‬
‫حي أن ‪ const‬ي‬ ‫ي‬
‫ر‬ ‫ن‬
‫معروفة يف وقت البجمة‪.‬‬

‫‪ .1.2‬انواع البيانات يف دارت‬


‫‪String‬‬ ‫‪‬‬
‫‪int‬‬ ‫‪‬‬
‫‪double‬‬ ‫‪‬‬
‫‪bool‬‬ ‫‪‬‬
‫‪List‬‬ ‫‪‬‬
‫‪Set‬‬ ‫‪‬‬
‫‪enum‬‬ ‫‪‬‬

‫السالسل‬ ‫‪.1.2.2‬‬
‫; "‪String s1 = "test‬‬

‫االعداد‬ ‫‪.1.2.1‬‬
‫; ‪int i = 5‬‬

‫; ‪double d = 5.5‬‬

‫;()‪String si = i.toString‬‬

‫;()‪String sd = d.toString‬‬

‫;)‪print(i‬‬

‫;)‪print(d‬‬

‫;)‪print(si‬‬

‫;)‪print(sd‬‬

‫يمكنك تحويل السلسلة اىل رقم بالدالة‬


‫()‪parse‬‬
‫مثال‬

‫;"‪String si = "5‬‬

‫;"‪String sd = "5.5‬‬

‫;)‪int i = int.parse(si‬‬

‫;)‪double d = double.parse(sd‬‬

‫‪ .1.2.2‬النوع ‪Boolean‬‬
‫رن‬
‫قيمتي‪ ،‬إما صواب (‪ )true‬أو خطأ (‪)false‬‬ ‫تحمل إحدى‬

‫;‪bool test‬‬

‫‪ .1.2.2‬القوائم ‪Lists and Maps‬‬


‫تشبه المصفوفات‬

‫مثال‬

‫;] ‪List lst = [ 8, 3, 12‬‬

‫;)‪lst.add(4‬‬

‫;))‪print(lst.indexOf(4‬‬

‫;)‪print(lst‬‬

‫المجموعات ‪Sets‬‬ ‫‪.1.2.2‬‬


‫غب مرتبة حيث ال يمكنك الوصول‬
‫أيضا توفر دارت فئات المجموعات (تشبه القوائم) لكنها قوائم ر‬
‫للعنارص بفهرسها‪ ،‬وإنما تحتاج أن تستخدم الدوال‬

‫()‪ contains‬‬
‫() ‪ containsAll‬‬

‫مثال‬
Set ck = Set)(;

ck.addAll([ "o", "c", "r”]);

ck.add("o");

ck.remove("c");

print(ck);

print(ck.contains("o"));

print(ck.containsAll([ "c", "r"]);

‫ما هو المخرج ؟‬

Enumerations ‫ النوع‬.1.2.2
‫نحتاج هذا النوع إلنشاء نوع محدد القيم مثال‬

enum colorx { red, blue, white}

‫ التكرار‬.1.2
‫ن‬
:‫التكرار يف دارت يمكن أن يتم بإحدى األوامر التالية‬

for 
do 
while 

:1 ‫مثال‬

for (var i = 0; i < 10; i++) { print(i;)

9 ‫ اىل‬1 ‫يكرر من‬

:2 ‫مثال‬

while (condition){
‫‪// do something‬‬

‫}‬

‫مثال ‪:3‬‬

‫{‪do‬‬

‫‪// do some thing‬‬

‫}‬

‫)‪while (condition‬‬

‫ملحوظة‬
‫ن‬
‫‪ :For‬يفضل استخدامها يف التكرار معروف العدد َّأما ‪ while, do‬فتستخدمان للتكرار المعتمد عل‬
‫شط مع ر ن‬
‫ي‪.‬‬

‫سؤال‪ :‬ما الفرق بي ‪ while‬و ‪ do‬؟‬

‫‪Switch .1.2‬‬
‫مثل جافا ومعظم اللغات االخرى‪ ،‬توفر دارت أمر‪ switch‬الذي يستخدم لالختيار من ضمن خيارات‬
‫متعددة‪.‬‬

‫مثال‬

‫{ )‪switch (someVariable‬‬

‫; ‪case 1: // Do something; break‬‬

‫; ‪case 2: // Do something else‬‬

‫; ‪break‬‬

‫; ‪default: // It wasn't 1 or 2‬‬

‫;‪break‬‬

‫}‬

‫ملحوظة هامة‪:‬‬
‫ن‬
‫تالحظ نرصورة وجود األمر ‪ break‬يف نهاية كل خيار من خيارات ‪ switch‬فإذا لم تكن‪ break‬موجودة‬
‫التاىل ويستمر للذي يليه إذا لم يجد فيه ‪ break‬ولن يتوفق إال إذا وجد‬
‫البنامج لينفذ الخيار ي‬
‫فسينتقل ر‬
‫‪ Break‬أو وصل لنهاية ‪.switch‬‬
‫ن‬
‫األمر ‪ switch‬يف ‪ Dart‬يتعامل مع نوع ‪ integer‬أو ‪. string‬‬

‫‪ .1.22‬األمر ‪If‬‬
‫بي تنفيذ خيارات مختلفة‬ ‫البنامج متسلسال‪ ،‬وتستخدم ‪ if‬نف حالة اتخاذ قرار ر ن‬
‫معي ر ن‬ ‫عادة يتم تنفيذ ر‬
‫ي‬
‫ن‬
‫(اشبة باألمر ‪ )switch‬حيث ستحتاج استخدام هذا األمر يف حالة تنفيذ شطية تعتمد عل صحة‬
‫الرسط أو عدمه لتنفيذ أمر أو أوامر ما‪.‬‬

‫مثال‪:‬‬

‫)‪if (condition‬‬

‫‪// do some thing‬‬

‫‪else‬‬

‫‪// do some thing else‬‬

‫‪ .1.22‬ال ئ‬
‫ش ‪viod‬‬
‫ئ ن‬
‫يعت إذا وضعت هذا األمر أمام دالة‬
‫تستخدم دارت مثلها مثل بقية اللغات ‪ void‬للدالة عل ال س ي‬
‫ن‬
‫فيعت أنها ال ترجع قيمة‬
‫ي‬
‫مثال‬

‫{ )(‪void func‬‬

‫‪//Code‬‬

‫}‬
‫ن‬
‫تختلف دارت يف أنك ال تحتاج وضع ‪ void‬أمام الدالة‪ ،‬فقط يكفيك أن ال تضيف أمر ‪ return‬داخل‬
‫َ‬
‫الدالة‪ ،‬فتفهم دارت أن الدالة من النوع ‪.Void‬‬
‫‪ .1.21‬العوامل يف دارت ‪operators‬‬
‫كبب من العوامل‬
‫تحتوي دارت عل عدد ر‬
‫‪ .1.22‬الكائنات يف دارت )‪(objects‬‬
‫ر‬
‫كاالت‪:‬‬ ‫يمكنك تعريف ‪ myClass‬الفئة‬
‫ي‬
‫{ ‪class myClass‬‬

‫‪// body of the class here‬‬

‫}‬

‫متغبين‪ ،‬نطلق عليهما ‪instance variables‬‬


‫التاىل يعرف فئة اسمها ‪ person‬تحتوي عل ر‬
‫المثال ي‬
‫وتحتوي الفئة أيضا عل دالة نطلق عليها طريقة ‪method‬‬
‫الكود‪:‬‬

‫{ ‪class person‬‬

‫; ‪String firstName‬‬

‫;‪String lastName‬‬

‫{ )(‪String sayName‬‬

‫;" ‪return "$lastName, $firstName‬‬

‫}‬

‫}‬

‫ملحوظة‬
‫ر‬
‫الت نستخدمها ونتعامل معها‬ ‫ئ‬
‫وه ي‬‫كمتغب وإنما ننش منها كائنات )‪ (objects‬ي‬
‫ر‬ ‫الفئة غالبا ال نستخدمها‬
‫كمتغبات داخل برامجنا‬
‫ر‬

‫دالة من سطر واحد ‪:‬‬

‫يل‬
‫عند كتابة دالة مكونة من سطر واحد يمكنك أن تستخدم الرمز (>=) كما ي‬
‫;))(‪void main() => runApp(MyApp‬‬
‫يل ‪:‬‬
‫ويمكن كتابتها بالطريقة التقليدية كما ي‬
‫{ )(‪void main‬‬
‫;))(‪runApp(MyApp‬‬
‫}‬

‫املراجع‬
‫‪Beginning App Development with Flutter, Create Cross-Platform Mobile Apps, Rap Payne, 2019‬‬

‫الرجوع جلدول احملتوايت‬


‫الباب الثالث‬

‫مقدمة عن الودجيت‬
‫‪Everything Is Widgets‬‬
‫ماهي الودجيت )‪(widget‬‬

‫الودجيت هي مصطلح واسع يمكن أن يشير إلى‪:‬‬

‫عنصر واجهة مستخدم رسومية )‪( GUI‬‬ ‫‪-‬‬


‫تطبيق صغير يمكنه عرض المعلومات و ‪ /‬أو التفاعل مع المستخدم ‪.‬‬ ‫‪-‬‬

‫ويمكن أن يكون الودجيت‪:‬‬

‫أولي مثل زر )‪ (button‬أو شريط تمرير )‪ (scroll bar,‬أو تسمية )‪ (label‬أو مربع حوار )‪ (dialog box‬أو‬ ‫‪-‬‬
‫خأنة اختيار)‪(check box‬‬
‫ً‬ ‫ً‬
‫يمكن أن يكون شيئًا أكثر تطورا قليال مثل مربع البحث أو الخريطة الصغيرة أو الساعة أو عداد الزوار أو‬ ‫‪-‬‬
‫محول وحدة‪.‬‬

‫في مجال الحوسبة ‪ ،‬أصبح مصطلح الودجيت شائعًا عندما بدأت أنظمة التشغيل في دعم واجهة المستخدم الرسومية‪ .‬حيث تم‬
‫استخدامه لإلشارة إلى كل عنصر من شأنه أن يشكل واجهة مستخدم رسومية للتطبيق‪.‬‬

‫كل من الزر أو شريط التمرير أو العالمة أو مربع االختيار أو اللوحة أو زر الخيار باسم عناصر واجهة المستخدم )‪.(GUI‬‬ ‫يُعر‬

‫أيضًا باسم عناصر التحكم‪.‬‬ ‫في فيجوال بيسك ‪ ،‬كأنت تُعر‬

‫الويدجيت المبنية في فلتر (‪)Build-in Flutter widgets‬‬


‫تأتي فلتر بعدد كبير من الودجيتس (‪ )widgets‬التي يمكنك تستطيع استخدامها في إنشاء تطبيقاتك‬

‫من أأنواعها التالي‪:‬‬

‫‪Value widgets‬‬ ‫‪‬‬


‫‪Layout widgets‬‬ ‫‪‬‬
‫‪Navigation widgets‬‬ ‫‪‬‬
‫‪Other widgets‬‬ ‫‪‬‬

‫هنالك كثير من األنواع االخرى التي سيأتي ذكرها عند الحاجة لها‪.‬‬
‫ودجيتس القيمة (‪)value widgets‬‬
‫يحتوي هذا النوع من الودجيتس على قيمة‪ ،‬ربما تأتي القيم من التخزين المحلي‪ ،‬أو من خدمة على األنترنت ‪،‬‬ ‫•‬
‫أو من المستخدم نفسه‪.‬‬
‫يتم استخدام هذه الودجيتس لعرض القيم للمستخدم والحصول على قيم من المستخدم إلى التطبيق‪.‬‬ ‫•‬
‫أمثلة لهذا النوع‪:‬‬ ‫•‬

‫‪ :Text widget‬يعرض نص محدود‬ ‫•‬


‫‪ :Image widget‬تعرض صورة‬ ‫•‬

‫الصورة التالية توضح أمثلة اخرى‪:‬‬ ‫•‬

‫ويدجيتس التخطبط (‪)Layout widgets‬‬


‫تتيح لنا هذه الودجيتس التحكم في إنشاء تخطبط الشكل بالصورة التي نريد‪.‬‬

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

‫يحتوي فلتر على مكتبة غنية من ويدجيتس التخطيط (‪ ،.)layout widgets‬منها‪:‬‬


‫ودجيدتس التنقل (‪):navigation widgets‬‬

‫عندما يحتوي تطبيقك على عدة مشاهد ("شاشات" ‪" ،‬صفحات" ‪ ،‬كل ما تريد االتصال به) ‪ ،‬ستحتاج إلى طريقة للتنقل بينها‪.‬‬

‫في هذه الحالة ستستخدم ودجيدتس التنقل‪ .‬التي تتحكم في كيفية التنقل بين المشاهد‪ .‬عادة ما يتم ذلك عندما ينقر المستخدم على زر‬
‫التنقل الذي يوجد على شريط عالمات التبويب أو في درج ينزلق من الجأنب األيسر من الشاشة‪.‬‬

‫بعض امثلة لودجيتس تنقل‪:‬‬

‫ودجيتس متنوعة‬
‫السابقة وسيأتي الحديث عنها في وقت الحق‪.‬‬ ‫هنالك ويدجيدتس ال تندرج تحت التصاني‬

‫منها‪:‬‬

‫الويدجيتس القياسية ‪Standard widgets‬‬


‫‪ GridView‬يضع الويدجيتس كشبكة قابلة للتمرير‪.‬‬ ‫‪‬‬
‫‪ ListView‬يضع الويدجيتس كقائمة قابلة للتمرير‬ ‫‪‬‬
‫المكدس(‪ :)Stack‬يضع ويدجيت فوق ويدجيت آخر‪.‬‬ ‫‪‬‬
‫الحاوية (‪ :)Container‬تستخدم الحاويات لفصل الويدجيتس‪ ،‬أو إلضافة حدود أو هوامش ‪.‬‬ ‫‪‬‬

‫يمكنك تغيير خلفية الجهاز عن طريق وضع التخطيط بالكامل في حاوية وتغيير لون الخلفية أو صورتها‪.‬‬

‫تحتوي الحاوية على ويدجيت واحد ( ابن) ولكن يمكن أن يكون هذا االبن صفًا أو عمودًا أو حتى جذر شجرة ويدجيت‬

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

‫ويجيت العرض الشبكي ‪GridView‬‬


‫يمكن استخدام ويدجيت العرض الشبكي لوضع الويدجيتس كقائمة ثنائية األبعاد ‪ .‬يوفر العرض الشبكي قائمتين معدتين‬
‫مسبقًا ‪ ،‬أو يمكنك بناء شبكتك المخصصة ‪ .‬عندما يكتشف العرض الشبكي أن محتوياته طويلة جدًا بحيث ال تتناسب مع‬
‫مربع التجسيد ‪ ،‬يتم اضافة التمريره تلقائيًا‪.‬‬
‫عرض القائمة‪ListView‬‬
‫ً‬
‫طويال جدًا بالنسبة لمربع العرض ‪.‬‬ ‫ويدجيت عرض القائمة يشبه العمود ‪ ،‬لكنه يوفر التمرير تلقائيًا عندما يكون محتواه‬
‫بتحديد الحد األقصى لعرض البكسل ‪.‬‬

‫مالحظة‪ :‬عند عرض قائمة ثنائية األبعاد ‪ ،‬من المهم تحديد الصف والعمود الذي تشغله الخلية (على سبيل المثال ‪ ،‬اإلدخال‬
‫في عمود "السعرات الحرارية" لصف "األفوكادو")‬

‫المكدس‪Stack‬‬
‫يستخدم المكدس لترتيب الويدجيتس فوق ويدجيت أساسي (غالبًا ما يكون صورة)‪ .‬يمكن أن تتداخل الويدجيتس بشكل كامل‬
‫أو جزئي مع الويدجيت األساسي‪.‬‬
‫البطاقة ‪Card‬‬
‫البطاقة‪ :‬ينظم المعلومات ذات الصلة في صندوق ذي زوايا دائرية وظل مسقط‪ .‬البطاقة موجودة في مكتبة المواد ‪،‬‬
‫وتحتوي على معلومات متصلة ببعضها ويمكن أن تتكون البطاقة من أي ويدجيت تقريبًا ‪ ،‬ولكن غالبًا ما يتم استخدامها‬
‫مع ‪.ListTile‬‬

‫تحتوي البطاقة على ابن واحد ‪ ،‬ولكن يمكن أن يكون هذا االبن عمودًا أو صفًا أو قائمة أو شبكة أو ويدجيت آخر يدعم عدة‬
‫ابناء‪ .‬بشكل افتراضي ‪ ،‬تقوم البطاقة بتقليص حجمها إلى ‪ 2 × 2‬بكسل‪ .‬يمكنك استخدام ‪ SizedBox‬لتقييد حجم البطاقة‪.‬‬
‫تأثيرا ثالثي األبعاد‪ .‬يسمح لك تغيير خاصية‬
‫ً‬ ‫في فلتر ‪ ،‬تتميز البطاقة بزوايا مستديرة قليالً وظل منخفض ‪ ،‬مما يمنحها‬
‫ارتفاع البطاقة بالتحكم في تأثير الظل المسقط‪ .‬على سبيل المثال ‪ ،‬يؤدي تعيين االرتفاع إلى ‪ ، 04‬إلى رفع البطاقة بصريًا‬
‫بعيدًا عن السطح ويؤدي إلى زيادة انتشار الظل‪.‬يؤدي تحديد قيمة غير مدعومة إلى تعطيل الظل المسقط بالكامل‪.‬‬

‫ويدجيت ‪ListTile‬‬
‫للحصول على طريقة سهلة إلنشاء صف يحتوي على ‪ 3‬أسطر نصية وأيقونات بادئة وزائدة اختيارية‪ .‬يُستخدم ‪ListTile‬‬
‫كويدجيت صف متخصصة من مكتبة المواد ‪ ،‬بشكل شائع في ‪ Card‬أو ‪ ListView‬ولكن يمكن استخدامه في مكان آخر‪.‬‬
‫المراجع‬

 Techopedia, https://www.techopedia.com :

• Beginning App Development with Flutter, Create Cross-Platform


Mobile Apps, Rap Payne, 2019

• https://flutter.dev/docs/development/ui/layout

‫الرجوع جلدول احملتوايت‬


‫الباب الرابع‬

‫استخدام الويدجيتس‬
‫في هذا الباب سنقدم أمثلة للويدجيتس األكثر استخداما ً وكيفية كتابة أكوادها في تطبيقك وكيفية االستفادة من خصائصها في‬
‫تعديل مظهرها‪.‬‬

‫سنتحدث في هذا الباب عن الويدجيتس التالية‪:‬‬

‫•‬ ‫‪Container‬‬

‫•‬ ‫‪Text‬‬

‫•‬ ‫‪Image‬‬

‫•‬ ‫‪Icon‬‬

‫•‬ ‫‪RaisedButton‬‬

‫•‬ ‫‪PlaceHolder‬‬

‫•‬ ‫‪Row‬‬

‫•‬ ‫‪Column‬‬
‫الحاوية (‪) Container‬‬
‫يتم استخدامها إلحتواء ودجيت بداخلها‪ .‬فهي كما يبين اسمها تحتوي على ويدجيت اخرى‪ ،‬في هذه الحالة تكون الحاوية هي‬
‫االب والويدجيت الذي بداخلها هو ابن (‪.)child‬‬

‫وقد تكون الحاوية هي نفسها داخل ويدجيت اخر (ابن لويدجيت اعلى)‪.‬‬

‫تسمح لك الحاوية بتطبيق مجموعة متنوعة من الصفات (الميزات)‪ ،‬مثل‪:‬‬

‫لون الخلفية‬ ‫‪‬‬


‫محاذاة االبن داخل الحاوية‬ ‫‪‬‬
‫تعيين بعض القيود على حجم االبن‬ ‫‪‬‬
‫تطبيق بعض الزخرفة‬ ‫‪‬‬

‫مثال ‪1‬‬

‫هنا توجد الحاوية داخل ويدجيت اب هو ‪ ،Center‬وهي ليس بداخلها ويدجيت‪( .‬هي ابن للويدجيت ‪)Center‬‬

‫(‪Center‬‬
‫(‪child: Container‬‬
‫‪decoration: BoxDecoration(border: Border.all()),‬‬
‫‪height: 200.0,‬‬
‫‪width: 200.0,‬‬
‫‪),‬‬
‫‪),‬‬

‫ويدجيت النص (‪)Text‬‬


‫يستخدم ويدجيت النص إلظهار نص محدود في تطبيقك‪.‬‬

‫ابسط صيغة له‬

‫‪Text(‘Hello world’),‬‬

‫مثال ‪0‬‬

‫هنا الحاوية توجد داخل ‪ ،Center‬ويوجد بداخلها ابن هو ويدجيت النص ‪Text‬‬
‫(‪Center‬‬
‫(‪child: Container‬‬
‫‪height: 200.0,‬‬
‫‪width: 200.0,‬‬
‫‪child: Text("This is a text"),‬‬
‫‪),‬‬
‫‪),‬‬

‫ويدجيت الصورة (‪)Image widget‬‬


‫عرض الصور‪.‬‬ ‫اظهار صور على التطبيق الخاص بك هي ميزة مهمة حيث ال يكاد يخلو تطبيق اليوم من وظائ‬

‫يمكنك استخدام ويدجيت الصورة إلظهار صورة في تطبيقك‬

‫تحديد مصدر الصورة (‪)image source‬‬

‫صورة مضمنة (‪ : )embedded in the app‬هنا تكون الصورة موجودة داخل التطبيق‬ ‫‪‬‬
‫من االنترنت‬ ‫‪‬‬

‫اذا أردت استخدام صورة ثابتة في تطبيق (ال تتغير ابدا خالل عمر تطبيقك مثل الشعار أو الزخار )‪ ،‬فيجب أن تكون صورة‬
‫مضمنة‪.‬‬

‫مثال إلظهار صورة مضمنة‬


‫لعرض صورة مضمنة يجب أوال وضع الصورة في مجلد التطبيق افتح الملف ‪ pubspec.yaml‬ثم عدل فيه لتضع مسار (مكان)‬
‫الصورة فيه‪ ،‬مثال‪ ،‬بافتراض أن الصورة اسمها ‪ ،photo1.jpg‬وأنت قد وضعتها في مجلد اسمه ‪ images‬داخل التطبيق‪ ،‬فستضيف‬
‫السطر التالي في الملف ‪ pubspec.yaml‬كما يلي‪:‬‬

‫‪flutter:‬‬

‫‪assets:‬‬

‫‪- assets/images/photo1.png‬‬

‫ثم تظهر الصورة في ويدجيت الصورة كما يلي‪:‬‬

‫‪Image.asset('assets/images/photo1.jpg'),‬‬

‫أما إذا أردت صورة من االنترنت‪ ،‬فتستخدم أمر كما يلي داخل ويدجيت الصورة‪:‬‬

‫‪Image.network(imageUrl),‬‬
‫تغيير حجم الصورة (‪)Sizing an image‬‬
‫عادة يتم وضع الصورة داخل حاوية‪ ،‬ويتم استخدام خيارات ‪ BoxFit‬للتحكم في حجم الصورة وكيف تتناسب مع الحاوية التي تم‬
‫وضعها فيها‪.‬‬

‫من خيارات ‪ BoxFit‬ما يلي‪:‬‬

‫‪fill‬‬ ‫•‬

‫‪cover‬‬ ‫•‬

‫‪fitHeight‬‬ ‫•‬

‫‪fitWidth‬‬ ‫•‬

‫‪contain‬‬ ‫•‬

‫مثال‬

‫في هذا المثال تم وضع ويدجيت الصورة داخل حاوية‪ ،‬والحاوية توجد داخل ويدجيت التوسيط ‪.Center‬‬

‫‪.‬‬

‫(‪Center‬‬
‫(‪child: Container‬‬
‫‪height: 200.0,‬‬
‫‪width: 200.0,‬‬
‫‪child:‬‬
‫‪Image.network("https://flutter.io/images/flutter-mark-square-100.png"),‬‬
‫‪),‬‬
‫‪),‬‬

‫انواع الصور التي يمكن ان تستخدم مع ويدجيت الصورة‪:‬‬


‫‪JPEG‬‬ ‫•‬

‫‪PNG‬‬ ‫•‬

‫‪GIF‬‬ ‫•‬

‫‪Animated GIF‬‬ ‫•‬

‫‪WebP‬‬ ‫•‬

‫‪Animated WebP‬‬ ‫•‬

‫‪BMP‬‬ ‫•‬

‫‪WBMP‬‬ ‫•‬
‫ويدجيت األيقونة (‪)Icon‬‬
‫ويدجيت األيقونة يستخدم إلظهارأيقونات على تطبيقك‪.‬‬

‫يحتوي فلتر على مجموعة كبيرة من األيقونات (‪.)rich set of built-in icons‬‬

‫يمكنك الوصول القائمة كاملة من الرابط التالي‪:‬‬

‫•‬ ‫‪https://api.flutter.dev/flutter/material/Icons-class.html‬‬

‫مثال ‪1‬‬

‫في هذا المثال تم وضع ويدجيت األيقونة داخل حاوية‪ ،‬والحاوية داخل ويدجيت توسيط‪.‬‬

‫(‪Center‬‬
‫(‪child: Container‬‬
‫‪height: 200.0,‬‬
‫‪width: 200.0,‬‬
‫‪child: Icon(Icons.flag),‬‬
‫‪),‬‬
‫‪),‬‬

‫مثال ‪0‬‬

‫هذا الكود يوضح كيف يمكنك االستفادة من بعض خصائص ويدجيت األيقونة إلظهار أيقونة (كيكة) بلون أحمر وحجم ‪022‬‬
Icon(
Icons.cake,
color: Colors.red,
size: 200,
)

PlaceHolder ‫ويدجيت‬
‫تحجز مكان في التطبيق‬

‫مثال‬

‫ داخل حاوية‬Placeholder ‫في هذا المثال تم وضع ويدجيت‬

Center(
child: Container(
height: 200.0,
width: 200.0,
child: Placeholder(),
),
),

Raisedbutton ‫ويدجيت‬
onPressed ‫ ويمكن تنفيذ كود معين عند الضغط على هذا الزر بوضعه في‬،‫ لعمل زر‬Raisedbutton ‫يمكنك استخدام ويدجيت‬
‫الموجودة في هذا الويجيت‬

‫مثال‬

Center(
child: Container(
height: 200.0,
width: 200.0,
child: RaisedButton(
onPressed: () => print("on pressed"),
child: Text("BUTTON"),
color: Colors.blue,
‫‪),‬‬
‫‪),‬‬
‫‪),‬‬

‫ويدجيت العمود (‪)Column Widget‬‬


‫تستطيع إنشاء عمود مكون من عدد من الخاليا باستخدام هذا الودجيت ‪ ،‬حيث يمكن وضع ودجيت في كل خلية من خاليا العمود‬
‫(تعتبر هذه الويدجيتس الموجودة داخل خاليا العمود أبناء (‪.)children‬‬

‫مثال‬

‫في الكود التالي تم وضع ويدجيت عمود داخل ويدجيت توسيط‪ .‬يتكون ويدجيت العمود من ثالث حاويات‪ ،‬كل حاوية بلون مختلف‪.‬‬

‫(‪Center‬‬
‫(‪child: Column‬‬
‫‪crossAxisAlignment: CrossAxisAlignment.center,‬‬
‫‪mainAxisAlignment:‬‬
‫‪MainAxisAlignment.spaceEvenly,‬‬
‫[>‪children: <Widget‬‬
‫(‪Container‬‬
‫‪height: 20.0,‬‬
‫‪width: 20.0,‬‬
‫‪color: Colors.red,‬‬
‫‪),‬‬
‫(‪Container‬‬
‫‪height: 20.0,‬‬
‫‪width: 20.0,‬‬
‫‪color: Colors.green,‬‬
‫‪),‬‬
‫(‪Container‬‬
‫‪height: 20.0,‬‬
‫‪width: 20.0,‬‬
‫‪color: Colors.yellow,‬‬
‫‪),‬‬
‫‪],‬‬
‫‪),‬‬
‫‪),‬‬

‫‪ .1.4‬ويدجيت السطر (‪)Row Widget‬‬


‫تستطيع إنشاء سطر مكون من عدد من الخاليا باستخدام هذا الودجيت ‪ ،‬حيث يمكن وضع ودجيت في كل خلية من خاليا السطر‬
‫(تعتبر هذه الويدجيتس الموجودة داخل خاليا السطرأبناء (‪.)children‬‬
‫مثال‬

.‫ كل حاوية بلون مختلف‬،‫ يتكون ويدجيت السطر من ثالث حاويات‬.‫في الكود التالي تم وضع ويدجيت سطر داخل ويدجيت توسيط‬

Center(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(
height: 20.0,
width: 20.0,
color: Colors.red,
),
Container(
height: 20.0,
width: 20.0,
color: Colors.green,
),
Container(
height: 20.0,
width: 20.0,
color: Colors.yellow,
),
],
),
),

‫المراجع‬
5. Beginning App Development with Flutter, Create Cross-Platform Mobile Apps, Rap Payne, 2019

‫الرجوع جلدول احملتوايت‬


‫الباب الخامس‬

‫ويدجيتس اإلدخال‬
‫مقدمة‬
‫هنالك مجموعة من الودجيتس تستخدم إلستقبال بيانات من المستخدم وتوصيلها لتطبيقك لمعالجتها أو اتخاذ قرار ِوفقا ً لها‪ .‬سنتحدث‬
‫في هذا الباب عنها ‪:‬‬

‫ويدجيت ‪TextField‬‬
‫تستخدم هذه الودجيت الدخال نص الى التطبيق‪ .‬هذه الويدجيتس لديها خاصية تسمى ‪ ،onChanged‬والتي تعمل بمجرد تغير القيم‬
‫المدخلة من المستخدم‪ .‬أي كلما يضغط المستخدم على مفتاح في لوحة المفاتيح ستستلم هذه الخاصية (‪)onChanged‬النص المدخل‬
‫ليتم معالجته‪.‬‬

‫مثال ‪1‬‬

‫في هذا المثال يقبل الويدجيت إدخال نص من المستخدم‪ ،‬وكلما ضغط المستخدم على حرف ستعمل ‪ onChanged‬وتخزن القيمة‬
‫المدخلة في المتغير ‪ valCpy‬ويتم طباعة هذا المدخل في نفس الوقت على الكونوسل باالمر ;)‪.print(valCpy‬‬

‫يمكن كتابة الكود بأي واحدة من الطريقتين ادناه (الفرق فقط في استخدام ‪ text‬أومتغيرنصي)‪.‬‬

‫; ‪String valCpy‬‬ ‫; ‪String valCpy‬‬


‫‪......‬‬ ‫‪......‬‬
‫‪.......‬‬ ‫‪.......‬‬
‫(‪TextField‬‬ ‫(‪TextField‬‬
‫{ )‪onChanged: (String val‬‬ ‫{ )‪onChanged: (text‬‬
‫;‪valCpy = val‬‬ ‫;‪valCpy = text‬‬
‫;)‪print(valCpy‬‬ ‫;)‪print(valCpy‬‬
‫‪},‬‬ ‫‪},‬‬
‫‪),‬‬ ‫‪),‬‬

‫مثال لو أدخلت كلمة سالم من الكبيورد في المثال أعاله ستعمل خاصية ‪ onChanged‬مع كل ضغطة على الكيبورد فيظهر في‬
‫الكونسول الناتج التالي‪:‬‬

‫استخدام ‪ TextField‬الدخال كلمة مرور‬

‫يمكنك التعديل في خواص الويدجيت ‪ TextField‬ليمكنك من استخدامه لبيانات ال ترى وإنما تظهر في مربع النص في شكل نجوم‪،‬‬
‫كما مبين في الكود التالي‪:‬‬
‫(‪TextField‬‬
‫‪obscureText: true,‬‬
‫(‪decoration: InputDecoration‬‬
‫‪labelText: 'Password',‬‬
‫‪),‬‬
‫;)‬

‫تعيين لوحة مفاتيح خاصة (‪)Special soft keyboard‬‬

‫يمكننا استخدام خاصية ‪ keyboardType‬في ويدجيت ‪ TextField‬إلظهار سوفت كيبورد لتقليل أخطاء اإلدخال‪ ،‬مثال لو كنت تريد‬
‫من المستخدم أن يدخل أرقام فقط فستختار ‪ TextInputType.number‬كما في الكود التالي‪:‬‬
‫(‪return TextField‬‬
‫‪keyboardType: TextInputType.number,‬‬
‫;)‬

‫هنالك انواع مختلفة من السوفت كيبورد‪ ،‬كما مبين ادناه‪.‬‬

‫مثال‬

‫مثال لو أردت عمل كلمة مرور من أرقام فقط‪ ،‬فيمكنك استخدام خاصية كلمة المرور وتحديد السوفت كيبورد ليكون رقمي كما مبين‬
‫أدناه‪:‬‬
‫تخصيص ويدجيت ‪ TextField‬الدخال ايميل (‪)Input email‬‬

‫المثال التالي يوضح كيف يمكنك مساعدة المستخدم إلدخال إيميل الى مربع النص‬
‫ويدجيت ‪Checkbox‬‬

‫يمكنك عمل مربع اختيار في تطبيقك باستخدام هذه الويدجيت ‪Checkbox‬‬

‫مثال‬

‫في المثال التالي تعمل الخاصية ‪ onChanged‬عند ما يضغط المستخدم على مربع االختيار ويطبع القيمة المنطقية على الكونسول‪.‬‬

‫(‪Checkbox‬‬ ‫(‪Checkbox‬‬
‫‪value: true,‬‬ ‫‪value: true,‬‬
‫)‪onChanged: (bool val) => print(val‬‬ ‫{)‪onChanged: (bool val‬‬
‫‪),‬‬ ‫;)‪print(val‬‬
‫;‪checkboxValue = val‬‬
‫;)}‬

‫المخرج‬

‫انشاء مربع اختيار داخل صف مع إضافة نص يوضح لم خصص مربع االختيار (صف داخلة ويدجيت مربع اختيار ‪ +‬ويدجيت نص)‬
‫ويدجيت ‪Radio button‬‬
‫زر ريديو في تطبيق في أبسط صوره‪ ،‬يكون كما يلي‪:‬‬

‫مثال ‪0‬‬

‫يمكنك اضافة خاصية ‪ onChanged‬لزر ريديو أو اضافة ‪ groupValue‬لربط عدد من ازرار الريديو مع بعض لتتيح للمستخدم‬
‫اختيار خيار واحد فقط من ضمن خيارات‪ ,‬ووضع كل االزرار في صف واحد (للتنسيق)‪.‬‬
Row(
children: <Widget>[
Radio(
value: 0,
groupValue : _radioValue,
onChanged : (int inValue) {
_radioValue = inValue;
}),

Radio (
value: 1,
groupValue : _radioValue,
onChanged : (int inValue) {
_radioValue = inValue;
}
)
]),

‫الكود والمخرج‬
‫مثال‬

Center(
child: Row(
children: <Widget>[
Radio(
value: 0,
groupValue : _radioValue,
onChanged : (int inValue) {
_radioValue = inValue;
}),
Radio (
value: 1,
groupValue : _radioValue,
onChanged : (int inValue) {
_radioValue = inValue;
}
)
]),
),

‫مثال‬

‫وضعها في صف‬
Center(
child: Row(
crossAxisAlignment:
CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: <Widget>[
Radio(
value: 0,
groupValue : _radioValue,
onChanged : (int inValue) {
_radioValue = inValue;
}),
Radio (
value: 1,
groupValue : _radioValue,
onChanged : (int inValue) {
_radioValue = inValue;
}
)
]),
),

‫مثال‬

• Center(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Radio(
value: 0,
groupValue : _radioValue,
onChanged : (int inValue) {
_radioValue = inValue;
}),
Text("Male"),
Radio (
value: 1,
groupValue : _radioValue,
onChanged : (int inValue) {
_radioValue = inValue;
}
),
Text("FeMale")
]),
),
Center(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Radio(
value: 0,
groupValue : _radioValue,
onChanged : (int inValue) {
_radioValue = inValue;
}),
Text("Male"),
Radio (
value: 1,
groupValue : _radioValue,
onChanged : (int inValue) {
_radioValue = inValue;
}
),
Text("FeMale")
]),
),
Sliders ‫ويدجيت‬
Slider(

label: _value.toString(),

min: 0, max: 100,

divisions: 100,

value: _value,

onChanged: (double val) => _value = val,

),

• var _value = 0.0;


.........

• Center(
child: Slider(
label: _value.toString(),
min: 0, max: 100,
divisions: 100,
value: _value,
onChanged: (double val) => _value = val,
),
),
)Dropdown menu( ‫ويدجيت القائمة المنسدلة‬
‫ويدجيت لعمل قائمة منسدلة في تطبيقك‬

enum SearchType { web, image, news, shopping }

....

Center(
child:
DropdownButton<SearchType>(
value: _searchType,
items: const <DropdownMenuItem<SearchType>>[
DropdownMenuItem<SearchType>(
child:Text('Web'),
value: SearchType.web,

DropdownMenuItem<SearchType>(
child:Text('Image'),
value: SearchType.image,
),
DropdownMenuItem<SearchType>(
child:Text('News'),
value: SearchType.news,
),
),

DropdownMenuItem<SearchType>(
child:Text('Shopping'),
value: SearchType.shopping,
),
],
onChanged: (SearchType val) => _searchType = val,
),
),

‫المراجع‬
6. Beginning App Development with Flutter, Create Cross-Platform Mobile Apps, Rap Payne, 2019

‫الرجوع جلدول احملتوايت‬


‫الباب السادس‬

‫اسكافول‬
‫ويدجيت اسكافولد ‪Scafold‬‬
‫يمكنك استخدام ويدجيت اسكافولد إلنشاء تطبيق محمول لألغراض العامة وتحتوي تقريبًا على كل ما تحتاجه إلنشاء تطبيق فعال‬
‫وسريع االستجابة‪.‬‬

‫يمكنك انشاء الكثير على اسكافولد مثل‬

‫‪‬‬ ‫‪AppBar & Body‬‬


‫‪‬‬ ‫‪Floating Action Button‬‬
‫‪‬‬ ‫‪Bottom Navigation Bar‬‬
‫‪‬‬ ‫‪Persistent Footer Buttons‬‬

‫‪AppBar & Body‬‬


‫ن‬
‫األدت من‬ ‫ال يكتمل تطبيق اسكافولد بدون استخدام ‪ ،AppBar & Body‬ألنهما يمثالن الحد‬
‫ن‬
‫األدت من تصميم المواد ( ‪a minimal Material‬‬ ‫الت يجب استخدامها إلنشاء الحد‬‫ر‬
‫الويدجيتس ي‬
‫‪)Design‬‬
‫ن‬
‫عب جسم سكافولد‬ ‫يمكنك وضع أي ويدجيتس تريد عرضها يف تطبيقك للمستخدم ر‬

‫ن‬ ‫ر‬
‫الت يمكنك اضافتها فيه‪ .‬حيث يمكنك وضع ويدجيت يف كل‬
‫الصور التالية توضح اجزاء ‪ AppBar‬ي‬
‫جزء من اجزائه‪.‬‬

‫‪:‬‬
:‫مثال‬

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(),
body:
Text('Hello World :'),
),
);
}

‫المخؤج‬
AppBar ‫يمكننا تعديل المثال السابق بإضافة خلفية وعنوان لـ‬

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Welcome to Kattabi Academy"),
backgroundColor: Colors.deepOrangeAccent,
),
body:
Center(child: Text('Hello World')),
),
);
}
}

‫المخرج‬
‫ مثل تغيير لون الخلفية واستخدام األيقونات بدالً من النص كعنوان‬AppBar ‫يمكننا اضافة خصائص مختلفة على شاشة‬
‫مثال تغيير العنوان من ويدجيت نص الى ويدجيت ايقونة‬

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Icon(Icons.home),
backgroundColor: Colors.deepOrangeAccent,
),
body:
Center(child: Text('Hello World')),
),
);
}
}
‫زر اإلجراء العائم ‪Floating Action Button‬‬
‫زر اإلجراء العائم هو زر رمز دائري يتم عرضه طوال الوقت وهو مخصص بشكل عام للترويج إلجراء أساسي أو األكثر‬
‫استخدا ًما على الشاشة‪ .‬مثالً بالنسبة لتطبيقات البريد اإللكتروني الشائعة مثل ‪ ، Gmail‬يتم استخدامه إلنشاء بريد إلكتروني جديد‪.‬‬
‫يتم إنشاء زر إجراء عائم باستخدام ويدجيت () ‪ FloatingActionButton‬بحد أدنى من معلمتين ُمنشئتين تسمى "‪ ":child‬و‬
‫"‪ ":onPressed‬يتم استخدام "‪ ":child‬إلضافة التصني بينما يتم استخدام "‪ ، ":onPressed‬والذي يتم استدعاؤه في كل مرة‬
‫يضغط فيها المستخدم على الزر ‪ ،‬لتشغيل اإلجراء المطلوب‪.‬‬

‫عرض وحدة التحكم‬

‫على الرغم من أنه يمكننا عرض النصوص في زر اإلجراء العائم ‪ ،‬إال أنه من االفضل استخدام الرموز ‪ /‬الصور بدالً من ذلك ‪،‬‬
‫لسببين هما‪:‬‬

‫‪ .1‬من المرجح أن تؤدي الرموز أو الصور إلى تحرك المستخدم‬

‫‪ .0‬من الصعب احتواء النص الطويل والهادئ داخل المساحة الصغيرة لزر اإلجراء العائم‬

‫مثال إضافة زر عائم عند الضغط عليه يقوم بطباعة الرسالة التالية في كونسول‬

‫‪You pressed the button...‬‬

‫;'‪import 'package:flutter/material.dart‬‬
‫;))(‪void main() => runApp(MyApp‬‬
‫{ ‪class MyApp extends StatelessWidget‬‬
‫‪@override‬‬
‫{ )‪Widget build(BuildContext context‬‬
‫(‪return MaterialApp‬‬
‫(‪home: Scaffold‬‬
‫‪///////////////////////////////////////////////////////////////‬‬
‫(‪appBar: AppBar‬‬
‫‪title: Icon(Icons.home), //Text("Welcome to Kattabi Academy"),‬‬
‫‪backgroundColor: Colors.deepOrangeAccent,‬‬
‫‪),‬‬
‫‪///////////////////////////////////////////////////////////////‬‬
‫‪body:‬‬
‫‪Center(child: Text('Hello World')),‬‬
‫‪/////////////////////////////////////////////////////////////////‬‬
‫(‪floatingActionButton: FloatingActionButton‬‬
‫‪child: Icon(Icons.add),‬‬
‫{)(‪onPressed:‬‬
‫;)"‪print("you pressed the button...‬‬
‫‪},‬‬
‫‪),‬‬
‫‪////////////////////////////////////////////////////////////////////‬‬
‫‪),‬‬
‫;)‬
‫}‬
‫}‬
)+(‫إضافة نص ليظهر داخل الزر العائم بدالً من األيقونة بدال من االيثونة‬

Text("add"),

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
///////////////////////////////////////////////////////////////
appBar: AppBar(
title:Text("Welcome to Kattabi Academy"),
backgroundColor: Colors.deepOrangeAccent,
),
///////////////////////////////////////////////////////////////
body:
Center(child: Text('Hello World')),
/////////////////////////////////////////////////////////////////
floatingActionButton: FloatingActionButton(
child: Text("add"),
onPressed:(){
print("you pressed the button...");
},
),
////////////////////////////////////////////////////////////////////
),
);
}
}
‫شريط التنقل السفلي ‪Bottom Navigation Bar‬‬
‫شريط التنقل السفلي ‪ ،‬يشبه ‪ AppBar‬فهو شريط أفقي في أسفل الشاشة‪ .‬يمكن أن يحتوي على عناصر متعددة ويمكنه استخدام‬
‫تسميات نصية أو رموز أو مزيج من كليهما‪.‬يتم إنشاء شريط التنقل السفلي بشكل عام لعرض الرسائل وكذلك لتوفير إجراءات‬
‫اختصارات محددة للصفحة‪.‬‬

‫توجد أداة تسمى "‪ "BottomNavigationBar‬إلنشاء نفس األداة ‪ ،‬ومع ذلك ‪ ،‬باستخدام "‪ "Scaffold‬و‬
‫"‪ "FloatingActionButton‬نستخدم أداة "‪ "BottomAppBar‬ألنها توفر مساحة لزر اإلجراء العائم وال تتداخل معه‪.‬‬

‫مثال يمكنك إنشاء شريط تنقل سفلي باستخدام "‪ AppBar "BottomAppBar‬مع شريط التنقل السفلي ايضا يمكننا عرض أدوات‬
‫متعددة داخل ‪ )(BottomAppBar‬باستخدام ويدجيت مثل ‪ )( Row‬تحتوي على ويدجيتس فرعية متعددة بداخلها‪ .‬يمكن أن‬
‫يحتوي شريط التنقل السفلي على مجموعة من النصوص والرموز‪ .‬يمكن أن تكون الرموز مجرد رمز عرض ثابت أو زر رمز مع‬
‫اإلجراءات المرتبطة به‬

‫مثال اضافة شريط التنقل السفلي‬

‫;'‪import 'package:flutter/material.dart‬‬
‫;))(‪void main() => runApp(MyApp‬‬
‫{ ‪class MyApp extends StatelessWidget‬‬
‫‪@override‬‬
‫{ )‪Widget build(BuildContext context‬‬
‫(‪return MaterialApp‬‬
‫(‪home: Scaffold‬‬
‫‪///////////////////////////////////////////////////////////////‬‬
‫(‪appBar: AppBar‬‬
‫‪title:Text("Welcome to Kattabi Academy"),‬‬
‫‪backgroundColor: Colors.deepOrangeAccent,‬‬
),
///////////////////////////////////////////////////////////////
body:
Center(child: Text('Hello World')),
/////////////////////////////////////////////////////////////////
floatingActionButton: FloatingActionButton(
child: Text("add"),
onPressed:(){
print("you pressed the button...");
},
),
bottomNavigationBar:BottomAppBar(
child: Text("bottom bar "),
),
),
);
}
}

‫مثال اضافة ايقونة مع النص في الشريط السفلي‬

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
///////////////////////////////////////////////////////////////
appBar: AppBar(
title:Text("Welcome to Kattabi Academy"),
backgroundColor: Colors.deepOrangeAccent,
),
///////////////////////////////////////////////////////////////
body:
Center(child: Text('Hello World')),
/////////////////////////////////////////////////////////////////
floatingActionButton: FloatingActionButton(
child: Text("add"),
//Icon(Icons.add),
onPressed:(){
print("you pressed the button...");
},
),
bottomNavigationBar:BottomAppBar(
child: Row(
children: <Widget> [
Text("bottom bar "),
Icon(Icons.home),

],
),
),
),
);
}
}

‫تغيير ارتفاع شريط التنقل السفلي‬

‫() وتحديد معلمة االرتفاع لها‬Container" ‫يمكنك زيادة حجم شريط التنقل السفلي عن طريق احاطة االبن بحاوية‬

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
///////////////////////////////////////////////////////////////
appBar: AppBar(
title:Text("Welcome to Kattabi Academy"),
backgroundColor: Colors.deepOrangeAccent,
),
///////////////////////////////////////////////////////////////
body:
Center(child: Text('Hello World')),
/////////////////////////////////////////////////////////////////
floatingActionButton: FloatingActionButton(
child: Text("add"),
//Icon(Icons.add),
onPressed:(){
print("you pressed the button...");
},
),
bottomNavigationBar:BottomAppBar(
child: Container(
height: 100.0,
child: Row(
children: <Widget> [
Text("bottom bar "),
Icon(Icons.home),

],
),
),
),

),
);
}
}

)persistentFooterButtons( ‫أزرار تذييل ثابتة‬


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

‫ فهو يشترك‬.‫يأخذ زر التذييل الثابت مجموعة من األدوات وليس له خصائص مرتبطة به مثل لون الخلفية أو االرتفاع وما إلى ذلك‬
. ‫في لون الخلفية مع خلفية اسكافولد‬

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
///////////////////////////////////////////////////////////////
appBar: AppBar(
title:Text("Welcome to Kattabi Academy"),
backgroundColor: Colors.deepOrangeAccent,
),
///////////////////////////////////////////////////////////////
body:
Center(child: Text('Hello World')),
/////////////////////////////////////////////////////////////////
floatingActionButton: FloatingActionButton(
child: Text("add"),
//Icon(Icons.add),
onPressed:(){
print("you pressed the button...");
},
),
bottomNavigationBar:BottomAppBar(
child: Container(
height: 100.0,
child: Row(
children: <Widget> [
Text("bottom bar "),
Icon(Icons.home),
],
),
),
),
persistentFooterButtons: <Widget>[
IconButton(icon:Icon(Icons.account_box), onPressed:null ,),
IconButton(icon:Icon(Icons.account_circle), onPressed:null ,)

], ),
);
}
}

‫تمرين‬
‫ في الدروس السابقة وعدل االكواد فيه‬Hello world‫ارجع لنسخ برنامجنا االول‬
‫غير الشريط العلوي مرة بنص عربي ومرة بايقونة‬ ‫‪‬‬
‫غير في جسم اسكافولد وبدل ‪ ،‬جرب تغيير لون الخلفية‬ ‫‪‬‬
‫اض ازرار سفلية في التطبيق‬ ‫‪‬‬
‫زر عائم‬ ‫‪‬‬
‫زر ثابت‬ ‫‪‬‬
‫وغيره‬ ‫‪‬‬

‫المراجع‬
‫‪https://proandroiddev.com/flutter-material-design-using-scaffold-appbar-body-bottom-navigation-‬‬
‫‪floating-action-f84d71e68c76‬‬

‫الرجوع جلدول احملتوايت‬


‫الباب السابع‬

‫تخطيط تطبيقك‬

‫تم جمع دروس هذا الباب من موقع فلتر التالي‪:‬‬

‫‪https://flutter.dev/docs/development/ui/layout‬‬
‫‪Stateful and stateless widgets‬‬ ‫‪.1.1‬‬
‫الويدجيت نوعان هما‬
‫‪stateful .1‬‬
‫‪stateless .0‬‬
‫النوع األول يتغير عندما يتفاعل المستخدم معه وأما النوع الثاني فيظل شكله ثابت ال يتغيروال يتفاعل مع المستخدم‬
‫أمثلة لألدوات (الويدجيتس ) التي ال تتفاعل مع المستخدم‪:‬‬

‫‪Icon‬‬ ‫‪‬‬
‫‪IconButton‬‬ ‫‪‬‬
‫‪Text‬‬ ‫‪‬‬
‫تعتبر هذه الويدجيتس ‪ Stateless widgets‬هي فئات فرعية ‪ subclass‬من الويدجيت ‪StatelessWidget‬‬

‫أما الويدجيت الديناميكية ‪ stateful widget‬فهي تغير مظهرها استجابةً لألحداث الناتجة عن تفاعالت المستخدم أوعندما‬
‫تتلقى البيانات‪.‬‬
‫امثلة لهذا النوع‬

‫‪Checkbox‬‬ ‫‪‬‬
‫‪Radio‬‬ ‫‪‬‬
‫‪Slider‬‬ ‫‪‬‬
‫‪InkWell‬‬ ‫‪‬‬
‫‪Form‬‬ ‫‪‬‬
‫‪TextField‬‬ ‫‪‬‬
‫تعتبر هذه األدوات فئات فرعية من ‪ StatefulWidget‬يتم تخزين حالة الويدجيت ‪ A widget’s state‬في كائن الحالة‬
‫‪ State object‬مما يفصل حالة األداة من مظهرها‪.‬‬
‫تتكون الحالة من القيم التي يمكن أن تتغير ‪ ،‬مثل القيمة الحالية لشريط التمرير أو ما إذا تم تحديد مربع اختيار‪.‬‬
‫عندما تتغير حالة األداة ‪ ،‬يقوم كائن الحالة ‪ state object‬باستدعاء الميثود التالي ( )‪ setState‬الذي يخبر اإلطار (الفريم‬
‫ويرك) بإعادة رسم األداة‬

‫انشاء تطبيق غير تفاعلي (ساكن)‬ ‫‪.1.1‬‬


‫عندما نتحدث عن التطبيقات غير التفاعلية في فلتر‪ ،‬فإننا نقصد تلك التي ترث صفات الويدجيت عديمة الحالة‬
‫(‪ ،)Stateless‬وقد نطلق عليها عديمة الحالة أو غير تفاعلية أو ساكنة‪.‬‬
‫في هذا الباب سنقوم بإنشاء تطبيق ساكن يحتوي على أدوات غير تفاعلية ‪ ،‬وسيكون تركيزنا على كيفية استخدام‬
‫الويدجيتس األساسية‪ ،‬واالستفادة منها في تنسيق تطبيقنا وإخراجه بصورة منظمة ومرتبة‪.‬‬
‫لو الحظت في كل التطبيقات التي نفذناها مسبقا‪ ،‬حتى التي تحتوي على ويدجيتس إدخال مثل ‪ Checkbox‬و ‪Radio‬‬
‫‪ button‬فإن شكلها ال يتغير في شاشة التطبيق لو نقرت عليها‪( ،‬رغم ان الدالة ‪ OnChanged‬يتم تنفيذها) ذلك ألن‬
‫الودجيت الجذر ‪ Root widget‬أخذ صفات الودجيت ‪ StatelessWidget‬بالوراثة ‪ ،‬مما يجعل التطبيق ساكنا وغير‬
‫تفاعلي‪ ،‬أي أن هذه الويدجيت ال تعيد اظهار التطبيق مرة ثانية على الشاشة ‪Do not redraw the widget‬‬
‫ انشاء تطبيق ساكن‬.1..1 .1.1
‫انشي تطبيق جديد‬
Hello world project
.‫ اختار اي واحدة منها‬،‫ يمكنك انشاء التطبيق بأربع طرق‬،‫كما تعلمت في الباب االول‬
:‫في التطبيق الذي أنشأته يهمنا ملفين هما‬

main.dart 
pubspec.yaml 
)‫الملف االول به كود المشروع والملف التاني به بيانات تهيئة المشروع مثل تحديد مسار الصور في تطبيقك (اين توجد‬
.‫سنبدل هذين الملفين بملفين اخرين‬
:)lib ‫افتح الملف التالي في المشروع (موجود في المجلد‬
main.dart

:‫امسح محتواه والصق فيه الكود التالي‬


:‫يمكنك نسخ الكود التالي من الموقع‬
https://github.com/flutter/website/blob/master/examples/layout/lakes/step6/lib/main.dart

import 'package:flutter/material.dart';

void main() {

runApp(MyApp());

class MyApp extends StatelessWidget {

@override

Widget build(BuildContext context) {

Widget titleSection = Container(

padding: const EdgeInsets.all(32),

child: Row(

children: [

Expanded(

/*1*/

child: Column(
crossAxisAlignment: CrossAxisAlignment.start,

children: [

/*2*/

Container(

padding: const EdgeInsets.only(bottom: 8),

child: Text(

'Oeschinen Lake Campground',

style: TextStyle(

fontWeight: FontWeight.bold,

),

),

),

Text(

'Kandersteg, Switzerland',

style: TextStyle(

color: Colors.grey[500],

),

),

],

),

),

/*3*/

Icon(

Icons.star,

color: Colors.red[500],

),

Text('41'),

],

),
);

Color color = Theme.of(context).primaryColor;

Widget buttonSection = Container(

child: Row(

mainAxisAlignment: MainAxisAlignment.spaceEvenly,

children: [

_buildButtonColumn(color, Icons.call, 'CALL'),

_buildButtonColumn(color, Icons.near_me, 'ROUTE'),

_buildButtonColumn(color, Icons.share, 'SHARE'),

],

),

);

Widget textSection = Container(

padding: const EdgeInsets.all(32),

child: Text(

'Lake Oeschinen lies at the foot of the Blüemlisalp in the Bernese '

'Alps. Situated 1,578 meters above sea level, it is one of the '

'larger Alpine Lakes. A gondola ride from Kandersteg, followed by a '

'half-hour walk through pastures and pine forest, leads you to the '

'lake, which warms to 20 degrees Celsius in the summer. Activities '

'enjoyed here include rowing, and riding the summer toboggan run.',

softWrap: true,

),

);

return MaterialApp(

title: 'Flutter layout demo',

home: Scaffold(

appBar: AppBar(
title: Text('Flutter layout demo'),

),

body: ListView(

children: [

Image.asset(

'images/lake.jpg',

width: 600,

height: 240,

fit: BoxFit.cover,

),

titleSection,

buttonSection,

textSection,

],

),

),

);

Column _buildButtonColumn(Color color, IconData icon, String label) {

return Column(

mainAxisSize: MainAxisSize.min,

mainAxisAlignment: MainAxisAlignment.center,

children: [

Icon(icon, color: color),

Container(

margin: const EdgeInsets.only(top: 8),

child: Text(

label,

style: TextStyle(
‫‪fontSize: 12,‬‬

‫‪fontWeight: FontWeight.w400,‬‬

‫‪color: color,‬‬

‫‪),‬‬

‫‪),‬‬

‫‪),‬‬

‫‪],‬‬

‫;)‬

‫}‬

‫}‬

‫كود ملف التهيئة‬ ‫‪.1.1‬‬


‫افتح الملف التالي في المشروع ‪pubspec.yaml‬‬
‫ازل عالمة ‪ #‬من اما االوامر التالية‪ ،‬وعدلها بحيث تكون كما يلي‪:‬‬

‫‪assets:‬‬
‫‪-‬‬ ‫‪images/lake.jpg‬‬

‫اضف الصورة للمشروع‬ ‫‪.1.1‬‬


‫انشي مجلد في المشروع باالسم ‪ images‬ثم الصق فيه الصورة التالية (باعتبار اسم الصورة هو ‪:)lake.jpg‬‬

‫نفذ التطبيق‬ ‫‪.1.1‬‬


‫بعد اكتمال الخطوات السابقة وهي‪:‬‬

‫انشاء مشروع جديد‬ ‫‪‬‬


‫تغيير ‪main.dart‬‬ ‫‪‬‬
‫تغيير ‪pubspec.yaml‬‬ ‫‪‬‬
‫وضع نسخة من الصورة ‪ lake.jpg‬في التطبيق‬ ‫‪‬‬
‫نفذ المشروع ومن المفترض أن يكون شكل التطبيق كما يلي‪:‬‬

‫تنسيق التطبيق‬ ‫‪.1.1‬‬


‫قبل تعديل التطبيق السابق ليصبح تفاعلي نحتاج أن نشرح أكواده‪ .‬سنركز على الكود الموجود في ‪ main.dart‬وسنبدأ‬
‫بتنسيق مظهر التطبيق (‪ )Layout‬وستكون الدروس القادمة شرح للويدجيتس التي تم استخدامها في التنسيق‬

‫واجهات المستخدم ‪UI‬‬ ‫‪.1.4‬‬


‫ذكرنا في درس سابق أن فلتر تستخدم الكود لبناء األشكال (المظهر)‪ ،‬كما تستخدمه أيضا لكيفية عمل التطبيق (السلوك)‬
‫‪ Presentation & behaviour‬وتستخدم في ذلك لغة دارت ‪ .Dart‬أيضا ذكرنا أن الويدجيت هى فئة ‪ class‬وتستخدم‬
‫في بناء واجهات التطبيق ‪ ،UIs‬عادة ما نستخدم مجموعة من الويدجيتس لعمل الواجهات‬

‫بداية التخطيط‬ ‫‪.1.7‬‬


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

‫يمكن أن تحتوي الويدجيت على ويدجيت أخري وهنا نستخدم كلمة ‪ child‬لنُعلم الويدجيت أن بداخلها ويدجيت ابن‬
‫وأيضا يمكن أن تحتوي الويدجيت على عدد كبير من الويدجيتس (أبناء) ونستخدم كلمة ‪ children‬مثل الويدجيت‬
‫‪ Row‬والويدجيت ‪Column‬‬

‫يمكنك إنشاء تخطيط عن طريق إنشاء ويدجيتس لبناء ويدجيتس أكثر تعقيدًا‪ .‬مثال لعرض الشكل أدناه فإننا نستخدم ‪3‬‬
‫ويدجيتس لعرض ثالثة أيقونات و‪ 3‬ويدجيتس نصية لوضعها تحت األيقونات وكل هذا المحتوي سيكون داخل ويدجيت‬
‫(غير مرئي) هو ويدجيت الصف ‪ Row‬يعني‬
‫‪3 Icons‬‬ ‫‪‬‬
‫)‪3 Text (used as labels‬‬ ‫‪‬‬

‫‪ .1.1.‬شجرة الويدجيتس (‪)Widget tree‬‬


‫الشكل التالي يوضح شجرة الويدجيتس المستخدم في الشكل السابق حيث تحتوي الشجرة على حاوية بداخلها صف بداخل‬
‫الصف ثالثة اعمدة كل عمود يحتوي على أيقونة وحاوية و داخل كل حاوية نص‬

‫‪ .1.11‬التنسيق باستخدام الصفوف واالعمدة‬


‫يعد الصف والعمود من أكثر أنماط التخطيط استخدا ًما‪ .‬يمكنك وضع مجموعة من الويدجيتس في صف أو عمود يمكن أن‬
‫تكون الويدجيت التابعة نفسها ص ًفا أوعمودًا أوويدجيت معقدة أخرى‪.‬‬
‫يمكنك تحديد كيفية محاذاة الصف أو العمود ألبنائه ‪ ،‬عموديًا وأفقيًا‪ .‬يمكنك تمديد أو تقييد الويدجيتس الخاصة باألبناء كما‬
‫يمكنك تحديد كيفية استخدام الويدجيت االبن للمساحة المتاحة للصف أو العمود‪.‬‬

‫مثال‬
‫يمكنك عمل الشكل التالي في تطبيقك بـ‪:‬‬

‫صف يحتوي على ابنيين‪:‬‬ ‫‪‬‬


‫عمود على اليسار‬ ‫‪‬‬
‫وصورة في اليمين‬ ‫‪‬‬

‫‪Row‬‬

‫‪Column‬‬

‫ويدجيت العمود نفسها في الشكل أعاله تحتوي على صفوف داخلها كما يظهر في الشكل أدناه‬

‫‪ .1.11‬أهمية الصف والعمود في التنسيق‬


‫يعد الصف والعمود أدوات مصغرة أساسية للتخطيطات األفقية والرأسية تسمح هذه األدوات ذات المستوى المنخفض‬
‫بأقصى قدر من التخصيص‪.‬‬
‫يقدم فلتر أيضًا أدوات متخصصة ذات مستوى أعلى قد تكون كافية الحتياجاتك‪ .‬على سبيل المثال ‪ ،‬بدالً من الصف ‪ ،‬قد‬
‫تفضل ‪ ListTile‬وهي أداة سهلة االستخدام مع خصائص للرموز األولية والزائدة ‪ ،‬وما يصل إلى ‪ 3‬أسطر من النص‪.‬‬
‫ً‬
‫طويال جدًا بحيث ال‬ ‫وبدالً من العمود ‪ ،‬قد تفضل ‪ ListView‬وهو تخطيط يشبه العمود يتم تمريره تلقائيًا إذا كان محتواه‬
‫يتناسب مع المساحة المتاحة‪ .‬هنا في دروسنا سنركز على الصف والعمود في التنسيق‬

‫‪ .1.11‬ويدجيت المحاذاة (‪)Aligning widgets‬‬


‫يمكنك التحكم في كيفية محاذاة صف أو عمود البنائه باستخدام خصائص ‪ mainAxisAlignment‬و‬
‫‪.crossAxisAlignment‬‬
‫بالنسبة للصف ‪ ،‬يعمل المحور الرئيسي أفقيًا ويعمل المحور المتقاطع رأسيًا‪ .‬بالنسبة للعمود ‪ ،‬يعمل المحور الرئيسي‬
‫عموديًا ويعمل المحور المتقاطع أفقيًا‪ .‬يوفر كل من ‪ MainAxisAlignment‬و ‪CrossAxisAlignment classes‬‬
‫خيارات مختلفة للتحكم في المحاذاة‬
‫ كود إلنشاء صف يحتوي على ثالث ويدجيتس‬.1.11
‫ فإنه يمكنك وضع أي عدد من الويدجيتس داخله‬،‫عند إنشاء ويدجيت صف‬
Row(
children :[
widget,
Widget,
Widget,
....
])
:‫ يمكنك استخدام كود كالتالي‬،‫مثال لوضع ثالث صور في صف‬

Row )
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Image.asset('images/pic1.jpg,)'
Image.asset('images/pic2.jpg,)'
Image.asset('images/pic3.jpg,)'
],
‫;)‬
‫هنا ستظهر الصور على نفس الصف وألننا استخدمنا ‪ spaceEvenly‬فستكون المسافات بين الصورة متساوية‬
‫لتجربة هذا الكود ‪:‬يجب أن تكون لديك ثالث صور في مجلد اسمه ‪ imaged‬داخل تطبيقك ويكون هذا المجلد معرف في‬
‫الملف ‪pubspec.yaml‬‬

‫‪ .1.11‬كود إلظهار ثالث صور رأسيا باستخدام ويدجيت العمود‬


‫تعمل األعمدة بنفس طريقة عمل الصفوف‪ .‬يوضح المثال التالي عمودًا مكونًا من ‪ 3‬صور ‪ ،‬يبلغ ارتفاع كل منها ‪122‬‬
‫بكسل‪ .‬يبلغ ارتفاع مربع التجسيد ‪( Render box‬في هذه الحالة ‪ ،‬الشاشة بأكملها) أكثر من ‪ 322‬بكسل ‪ ،‬لذا فإن تعيين‬
‫محاذاة المحور الرئيسي على ‪ spaceEvenly‬يقسم المساحة الرأسية الخالية بالتساوي بين كل صورة وفوقها وأسفلها‪.‬‬

‫الكود‬
‫(‪Column‬‬
‫‪mainAxisAlignment: MainAxisAlignment.spaceEvenly,‬‬
‫[ ‪children:‬‬
‫‪Image.asset('images/pic1.jpg'),‬‬
‫‪Image.asset('images/pic2.jpg'),‬‬
‫‪Image.asset('images/pic3.jpg,'),‬‬
‫‪],‬‬
‫;)‬

‫ملحوظة‬
‫لو قارنت بين كود الصف وكود العمود تجد أن الفرق فقط في الكلمة االولى ‪ Row‬أو ‪ Column‬باقي الكود كما هو‬

‫‪ .1.11‬تغيير حجم الويدجيتس ‪Sizing widgets‬‬


‫كبيرا جدًا بحيث ال يتناسب مع الجهاز ‪ ،‬يظهر نقش مخطط أصفر وأسود على طول الحافة المتأثرة‪.‬‬
‫عندما يكون التخطيط ً‬
‫يمكن تغيير حجم الويدجيتس ليتناسب داخل صف أو عمود باستخدام ويدجيت التوسع (‪)Expanded widget‬‬
‫الكود التالي يوضح استخدام هذه الويدجيت‪:‬‬
‫(‪Row‬‬
‫‪crossAxisAlignment: CrossAxisAlignment.center,‬‬
children :[
Expanded(child: Image.asset('images/pic1.jpg')),
Expanded (child: Image.asset('images/pic2.jpg')),
Expanded(child: Image.asset('images/pic3.jpg')),
]),
.flex ‫ لويدجيت التوسيع‬.)‫ يمكنك استخدام الخاصية المرنة (فليكس‬،‫إذا أردت أن تزيد المساحة التي تشغلها الصورة‬
.‫ للصورة الوسطى مما جعلها تشغل ضعف مساحتها‬0 ‫ في الكود التالي تم تغييرها إلى‬،1 ‫عامل فليكس االفتراضي هو‬

Row )
crossAxisAlignment: CrossAxisAlignment.center,
children :[
Expanded(child: Image.asset('images/pic1.jpg')),
Expanded(
flex: 2,
child: Image.asset('images/pic2.jpg')),
Expanded(
child: Image.asset('images/pic3.jpg')),
]),

Packing widgets ‫ تقليص الويدجيتس‬.1.11


‫ يشغل الصف أو العمود أكبر مساحة ممكنة على محوره الرئيسي قدر اإلمكان ولكن إذا كنت ترغب في‬، ‫بشكل افتراضي‬
:‫ فيمكنك تقليص حجمه الرئيسي إلى اقل شي ممكن باستخدام الخاصية التالية‬،‫جعل األبناء قريبة من بعض‬
MainAxisSize.min
‫مثال‬
Row(

mainAxisSize: MainAxisSize.min,

children :[

Icon(Icons.star, color: Colors.green[500]]),

Icon(Icons.star, color: Colors.green[500]),

Icon(Icons.star, color: Colors.green[500]),

Icon(Icons.star, color: Colors.black),

Icon(Icons.star, color: Colors.black),


‫‪],‬‬

‫ستظهر النجوم في تطبيقك بشكل كالتالي‬

‫‪ .1.14‬صفوف وأعمدة متداخلة‬


‫يمكنك إنشاء أعمدة داخل صف وداخل األعمدة صفوف وداخل الصفوف أعمدة كما تريد‬

‫في الصورة المرفقة‪ ،‬أنشأنا حاوية داخلها صف‬ ‫‪‬‬


‫وداخل الصف صورة وعمود‬ ‫‪‬‬
‫وداخل العمود صفين‬ ‫‪‬‬
‫الصف األول داخله نص وصف اخر‬ ‫‪‬‬
‫والصف الثاني داخله ثالثة أعمدة‬ ‫‪‬‬
‫داخل كل عمود منها أيقونة وصفين‬ ‫‪‬‬

‫‪ .1.17‬كود إنشاء النجوم مع النص‬


‫الكود التالي إلظهار الصف الذي يحتوي نص مع خمسة نجوم كما موضح في الصورالمرفقة‬

‫ملحوظة هامة‬
‫تم استخدام متغير هو ‪ starts‬من النوع ‪ var‬لحفظ كود إنشاء النجوم داخل صف بحيث يمكنك استخدام هذا المتغير في‬
‫مكان اخر بدال عن كتابة الكود مرة اخرى وهو يشبه بذلك استخدام الدوال في اللغات االخرى‬

‫(‪var stars = Row‬‬

‫‪mainAxisSize: MainAxisSize.min,‬‬

‫‪children[ :‬‬

‫‪Icon(Icons.star, color: Colors.green[500]),‬‬

‫‪Icon(Icons.star, color: Colors.green[500]),‬‬

‫‪Icon(Icons.star, color: Colors.green[500]),‬‬

‫‪Icon(Icons.star, color: Colors.black),‬‬

‫‪Icon(Icons.star, color: Colors.black),‬‬

‫‪],),‬‬

‫(‪final ratings = Container‬‬

‫‪padding: EdgeInsets.all(20),‬‬
child: Row(

mainAxisAlignment: MainAxisAlignment.spaceEvenly,

children :[

stars,

Text(‘102 Reviews',

style: TextStyle(

color: Colors.black,

fontWeight: FontWeight.w800,

fontFamily: 'Roboto',

letterSpacing: 0.5,

fontSize: 20,

),

),

],

),

),

‫ كود الصف الذي يلي صف النجوم‬.1.1.


.‫هذا الصف يحتوي على ثالثة اعمدة كل عمود يحتوي على ايقونة ونصين كما مبين في الصور المرفقة‬
final descTextStyle = TextStyle(

color: Colors.black,

fontWeight: FontWeight.w800,

fontFamily: 'Roboto',

letterSpacing: 0.5,

fontSize: 18,

height: 2,

);

// DefaultTextStyle.merge() allows you to create a default text

// style that is inherited by its child and all subsequent children.

final iconList = DefaultTextStyle.merge(

style: descTextStyle,

child: Container(

padding: EdgeInsets.all(20),

child: Row(

mainAxisAlignment: MainAxisAlignment.spaceEvenly,

children: [

Column(

children: [

Icon(Icons.kitchen, color: Colors.green[500]),

Text('PREP:'),

Text('25 min'),

],

),

Column(

children: [

Icon(Icons.timer, color: Colors.green[500]),

Text('COOK:'),
Text('1 hr'),

],

),

Column(

children: [

Icon(Icons.restaurant, color: Colors.green[500]),

Text('FEEDS:'),

Text('4-6'),

],

),

],

),

),

);
‫‪ .1.11‬كود الصورة مع العمود (الشكل النهائي)‬
‫متغير العمود األيسر يحتوي على نص وصف التقييم (النجوم) وصف لوصف الصورة (يحتوي ثالث أعمدة)‬

‫(‪final leftColumn = Container‬‬

‫‪padding: EdgeInsets.fromLTRB(20, 30, 20, 20),‬‬

‫(‪child: Column‬‬

‫[ ‪children:‬‬

‫‪titleText,‬‬

‫‪subTitle,‬‬

‫صف النجوم ‪ratings, //‬‬

‫صف من ‪ 3‬اعمدة ‪iconList, //‬‬

‫‪],‬‬

‫‪),‬‬

‫;)‬

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

‫(‪body: Center‬‬

‫(‪child: Container‬‬

‫‪margin: EdgeInsets.fromLTRB(0, 40, 0, 30),‬‬

‫‪height: 600,‬‬

‫(‪child: Card‬‬

‫(‪child: Row‬‬

‫‪crossAxisAlignment: CrossAxisAlignment.start,‬‬

‫[ ‪children:‬‬

‫(‪Container‬‬

‫‪width: 440,‬‬

‫‪child: leftColumn,‬‬

‫‪),‬‬
‫‪mainImage,‬‬

‫‪],‬‬

‫‪),‬‬

‫‪),‬‬

‫‪),‬‬

‫‪),‬‬

‫المراجع‬
‫تم جمع دروس هذا الباب من موقع فلتر التالي‪:‬‬ ‫‪‬‬
‫‪‬‬ ‫‪https://flutter.dev/docs/development/ui/layout‬‬
‫وتم شرح كل الدروس من هذا الموقع مباشرة في الفيديو التالي‪:.‬‬ ‫‪‬‬
‫‪‬‬ ‫‪https://youtu.be/IYUtIoXwto8‬‬

‫الرجوع جلدول احملتوايت‬


‫الباب الثامن‬

‫انشاء تطبيق تف اعلي‬

Create a custom stateful widget

:‫محتويات هذا الباب من موقع فلتر التالي‬

Adding interactivity to your Flutter app, https://flutter.dev/docs/development/ui/interactive


‫‪ .4.1‬دالة (طريقة) البناء (‪)build() method‬‬

‫يتم إنشاء كل ويدجيت في فلتر بواسطة دالة البناء) ‪ (build‬وتأخذ هذه الدالة ال ُمدخل من النوع (‪ )BuildContext‬فنكتب الكود كما يلي‪:‬‬

‫{ )‪Build (BuildContext context‬‬

‫‪// return widget‬‬

‫}‬

‫ال ُمدخل (‪ )BuildContext‬يحدد مكان الويدجيت في شجرة الويدجيت التي تخص تطبيقك‬

‫تستلم الدالة ‪ runApp‬الويدجيت الجذر (جذر شجرة الويدجيت) كمدخل لها)‪.‬‬

‫‪ .4.1‬ويدجيت الحالة (‪)Stateful widget‬‬


‫ذكرنا في دروس سابقة أن الويدجيت نوعان‬

‫‪ .1‬ويدجيت حالة أي يعيد رسم نفسه مع التغيرات ) (‪)Stateful‬‬


‫‪ .0‬عديم الحالة (ال يعيد رسم نفسه) (‪)Stateless‬‬

‫لذلك اطلقنا على األول ساكن وعلى الثاني ديناميكي‪ .‬بالنسبة للنوع الثاني (الديناميكي)‪ ،‬يتم القيام به عن طريق فئتين هما‪:‬‬

‫‪ .1‬فئة فرعية من ويدجيت الحالة ( ‪)a subclass of StatefulWidget‬‬


‫‪ .0‬فئة فرعية من فئة الحالة (‪)a subclass of State.‬‬

‫تحتوي فئة الحالة ( ‪ )state class‬على‪:‬‬

‫حالة الويدجيت القابلة للتغيير( ‪)mutable state‬‬ ‫‪‬‬


‫و دالة البناء )(‪build‬‬ ‫‪‬‬

‫فعندما تتغير حالة الويدجيت فإن كائن الحالة ( ‪ )state object‬سيستدعي الطريقة )(‪ setState‬التي تطلب من إطار العمل‬
‫(‪ )framework‬إعادة رسم الويدجيت (‪)redraw the widget‬‬

‫‪ .4.1‬بداية التحول الى التفاعل‬


‫في هذا الجزء ‪ ،‬ستقوم بإنشاء ويدجيت مخصصة (‪ )customized‬ذات حالة (تفاعلي) ‪.‬‬

‫ستقوم باستبدال ويدجتين بدون حالة هما النجمة الحمراء الصلبة والعدد الرقمي المجاور لها‪ ،‬بويدجيت مخصصة واحدة تدير صفًا‬
‫يحتوي على ويدجتين فرعيين هما ‪:‬‬

‫‪IconButton‬‬ ‫‪‬‬
‫‪Text‬‬ ‫‪‬‬

‫يتطلب تطبيق ويدجيت مخصص ذو حالة إنشاء فئتين‪:‬‬

‫فئة فرعية من ويدجيت الحالة (‪ )StatefulWidget‬لتعريف الويدجيت‬ ‫‪‬‬


‫فئة فرعية من الحالة تحتوي على حالة تلك الويدجيت وتعريف طريقة البناء للويدجيت‬ ‫‪‬‬
‫سنتعلم في هذا الجزء كيفية بناء ويدجيت اسمه ‪ FavoriteWidget‬لتعديل التطبيق (الساكن‪/‬عديم الحالة) الذي تم انشاءه في الباب‬
‫السابق ليصبح تطبيقا تفاعليا‪.‬‬

‫‪ .4.1‬انشاء فئة فرعية من ‪StatefulWidget‬‬

‫تدير فئة ‪ FavoriteWidget‬حالتها الخاصة بها‪ ،‬لذا فهي تعمل (‪ )overrides‬للدالة )(‪ createState‬بدالة تقوم بإنشاء كائن حالة‬
‫(‪)state object‬‬

‫يقوم اطار العمل باستدعاء )(‪ createState‬عندما يريد انشاء ويدجيت‬

‫في هذا المثال تقوم )(‪ createState‬بإرجاع ‪ instance‬من ‪_FavoriteWidgetState‬‬

‫الكود‬

‫{ ‪class FavoriteWidget extends StatefulWidget‬‬

‫‪@override‬‬

‫;)(‪_FavoriteWidgetState createState() => _FavoriteWidgetState‬‬

‫}‬

‫األعضاء أو الفئات التي تبدأ بشرطة سفلية (_) تعتبر خاصة (في لغة دارت)‬
‫‪Members or classes that start with an underscore (_) are private.‬‬

‫المصدر‪https://flutter.dev/docs/development/ui/interactive#managing-state :‬‬

‫خالصة هذا الدرس هو أننا سنستبدل األيقونة العادية التي في التطبيق بزر ايقونة‪ ،‬الن زر االيقونة لديه خاصية ‪ onPressed‬التي‬
‫سنضع فيها كود يغير شكل الويدجيت والقيمة الموجودة في النص من ‪ 42‬الى ‪ 41‬مثال‪.‬‬

‫تقوم الفئة ‪ _FavoriteWidgetState‬بتخزين البيانات القابلة للتغيير أي التي يمكن أن تتغير على مدار حياة الويدجيت‪.‬‬

‫عندما يتم تشغيل التطبيق ألول مرة ‪ ،‬تعرض واجهة المستخدم نجمة حمراء صلبة ‪ ،‬كحالة "مفضلة" ‪ ،‬إلى جانب ‪ 41‬إعجابًا ‪ .‬يتم‬
‫تخزين هذه القيم في حقلي ‪ _isFavorited‬و‪ _favoriteCount‬كما يلي‪:‬‬
‫تحدد الفئة أيضًا طريقة البناء (‪ )build() method‬التي تنشئ صفًا يحتوي على زر ونص (‪ )IconButton & text‬يمكنك‬
‫استخدام زر ايقونة ( ‪ ) IconButton‬بدالً من االيقونة ألنه يحتوي على خاصية ‪ onPressed‬التي تحدد وظيفة رد االتصال‬
‫)‪ (_toggleFavorite‬لمعالجة النقر ‪.‬‬

‫ستحدد وظيفة رد االتصال بعد ذلك‪.‬‬

‫تنبيه‪ :‬يؤدي وضع النص في ‪ SizedBox‬وتعيين عرضه إلى منع حدوث "قفزة"‪ ،‬يمكن مالحظتها عندما يتغير النص بين ‪ 42‬و‬
‫‪( 41‬ألن هذه القيم لها عروض مختلفة)‬

‫الدالة )(‪ _toggleFavorite‬التي تعمل عند الضغط على ‪ ، IconButton‬تستدعي الدالة )(‪setState‬‬
‫استدعاء )(‪ setState‬يخبر اإلطار بأن حالة األداة قد تغيرت وأن الويدجيت يجب إعادة رسمها ‪.‬‬
‫تقوم الدالة لـ )(‪ setState‬بتبديل واجهة المستخدم بين هاتين الحالتين‪:‬‬

‫ايقونة نجمة والرقم ‪41‬‬ ‫‪‬‬


‫وايقونة نجمة مفرغة والرقم ‪42‬‬ ‫‪‬‬

‫الكود‬

‫‪ .4.1‬وضع ويدجيت الحالة في شجرة الويدجيت‬


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

‫الكود‬

‫قم باستبدال االوامر المعلمة باالصفر في التطبيق الساكن بامر الويدجيت في التطبيق التفاعلي (ايضا معلم باالصفر)‪ ،‬كما يلي‪:‬‬

‫في التطبيق الديناميكلي‬ ‫في التطبيق الساكن‬


‫{ )‪Widget build(BuildContext context‬‬ ‫{ )‪Widget build(BuildContext context‬‬

‫(‪Widget titleSection = Container‬‬ ‫(‪Widget titleSection = Container‬‬

‫‪padding: const EdgeInsets.all(32),‬‬ ‫‪padding: const EdgeInsets.all(32),‬‬

‫(‪child: Row‬‬ ‫(‪child: Row‬‬

‫[ ‪children:‬‬ ‫[ ‪children:‬‬
Expanded( Expanded(

/*1*/ /*1*/

child: Column( child: Column(

crossAxisAlignment: crossAxisAlignment:
CrossAxisAlignment.start, CrossAxisAlignment.start,

children: [ children: [

/*2*/ /*2*/

Container( Container(

padding: const padding: const


EdgeInsets.only(bottom: 8), EdgeInsets.only(bottom: 8),

child: Text( child: Text(

'Oeschinen Lake Campground', 'Oeschinen Lake Campground',

style: TextStyle( style: TextStyle(

fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,

), ),

), ),

), ),

Text( Text(

'Kandersteg, Switzerland', 'Kandersteg, Switzerland',

style: TextStyle( style: TextStyle(

color: Colors.grey[500], color: Colors.grey[500],

), ),

), ),

], ],

), ),

), ),

/*3*/ /*3*/

FavoriteWidget(), Icon(
‫‪],‬‬ ‫‪Icons.star,‬‬

‫‪),‬‬ ‫‪color: Colors.red[500],‬‬

‫;)‬ ‫‪),‬‬

‫‪Text('41'),‬‬

‫‪],‬‬

‫‪),‬‬

‫;)‬

‫عندما تعيد تحميل التطبيق ‪ ،‬يجب أن يستجيب رمز النجمة اآلن لنقرات المستخدم ويتغير بين ‪ 42‬والنجمة المفرغة الى ‪ 41‬والنجمة‬
‫الحمراء‪.‬‬

‫‪. .4.1‬ادارة ويدجيت الحالة ‪Subclass State‬‬

‫فيما يلي أكثر الطرق شيوعًا إلدارة ويدجت الحالة‪:‬‬

‫‪ .1‬تدير الويدجيت الحالة الخاصة بها ذاتيا‬


‫‪ .0‬يدير االب حالة الويدجيتس االبناء‬
‫‪ .3‬االثنين معا‬

‫كيف تقرر النهج الذي تستخدمه؟‬

‫من يدير حالة الويدجيت الذكية؟‬

‫الويدجيت نفسها؟ الويدجيت االب ؟ ام االثنين؟ ام كائن اخر ؟‬

‫يجب أن تساعدك المبادئ التالية في اتخاذ قرار‪:‬‬

‫إذا كانت الحالة المعنية هي بيانات المستخدم ‪ ،‬على سبيل المثال الوضع المحدد أو غير المحدد لمربع االختيار‬ ‫‪‬‬
‫(‪ ،)Checkbox‬أو موضع شريط التمرير(‪ ،)slider‬فمن األفضل إدارة الحالة بواسطة الويدجيت الرئيسية (‬
‫األب)‪.‬‬
‫إذا كانت الحالة المعنية جمالية ‪ ،‬على سبيل المثال الرسوم المتحركة ‪ ،‬فمن األفضل إدارة الحالة بواسطة‬ ‫‪‬‬
‫الويدجيت نفسها‪.‬‬
‫إذا كنت في شك ‪ ،‬فابدأ بإدارة الحالة في الويدجيت االب‪.‬‬ ‫‪‬‬

‫‪ .4.1‬كود الويدجيت التفاعلي‬


‫يتكون الويدجيت التفاعلي من فئتين هما‬

Stateful widget ‫فئة فرعية من‬ 


State ‫فئة فرعية من الحالة‬ 

‫ في تطبيقك ومسحها ووضع الكود أدناه وتشغيل البرنامج سيظهر لك نفس شكل التطبيق السابق ولكن عند‬main.dart ‫يمكنك فتح‬
‫النقر على نجمة اإلعجاب سيتغير شكلها وتتغير قيمة عداد اإلعجاب‬

‫فيما يلي الكود كامال‬


import 'package:flutter/material.dart';

class FavoriteWidget extends StatefulWidget {

@override

_FavoriteWidgetState createState() => _FavoriteWidgetState();

class _FavoriteWidgetState extends State<FavoriteWidget> {

bool _isFavorited = true;

int _favoriteCount = 41;

void _toggleFavorite() {

setState(() {

if (_isFavorited) {

_favoriteCount -= 1;

_isFavorited = false;

} else {

_favoriteCount += 1;

_isFavorited = true;

});

@override

Widget build(BuildContext context) {

return Row(

mainAxisSize: MainAxisSize.min,

children: [
Container(

padding: EdgeInsets.all(0),

child: IconButton(

icon: (_isFavorited ? Icon(Icons.star) : Icon(Icons.star_border)),

color: Colors.red[500],

onPressed: _toggleFavorite,

),

),

SizedBox(

width: 18,

child: Container(

child: Text('$_favoriteCount'),

),

),

],

);

// ···

void main() {

runApp(MyApp());

class MyApp extends StatelessWidget {

@override

Widget build(BuildContext context) {

Widget titleSection = Container(

padding: const EdgeInsets.all(32),

child: Row(

children: [

Expanded(

/*1*/
child: Column(

crossAxisAlignment: CrossAxisAlignment.start,

children: [

/*2*/

Container(

padding: const EdgeInsets.only(bottom: 8),

child: Text(

'Oeschinen Lake Campground',

style: TextStyle(

fontWeight: FontWeight.bold,

),

),

),

Text(

'Kandersteg, Switzerland',

style: TextStyle(

color: Colors.grey[500],

),

),

],

),

),

/*3*/

FavoriteWidget(),

],

),

);

Color color = Theme.of(context).primaryColor;

Widget buttonSection = Container(

child: Row(

mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [

_buildButtonColumn(color, Icons.call, 'CALL'),

_buildButtonColumn(color, Icons.near_me, 'ROUTE'),

_buildButtonColumn(color, Icons.share, 'SHARE'),

],

),

);

Widget textSection = Container(

padding: const EdgeInsets.all(32),

child: Text(

'Lake Oeschinen lies at the foot of the Blüemlisalp in the Bernese '

'Alps. Situated 1,578 meters above sea level, it is one of the '

'larger Alpine Lakes. A gondola ride from Kandersteg, followed by a '

'half-hour walk through pastures and pine forest, leads you to the '

'lake, which warms to 20 degrees Celsius in the summer. Activities '

'enjoyed here include rowing, and riding the summer toboggan run.',

softWrap: true,

),

);

return MaterialApp(

title: 'Flutter layout demo',

home: Scaffold(

appBar: AppBar(

title: Text('Flutter layout demo'),),

body: ListView(

children: [

Image.asset(

'images/lake.jpg',

width: 600,

height: 240,

fit: BoxFit.cover,
),

titleSection,

buttonSection,

textSection,

],),

),

);

Column _buildButtonColumn(Color color, IconData icon, String label) {

return Column(

mainAxisSize: MainAxisSize.min,

mainAxisAlignment: MainAxisAlignment.center,

children: [

Icon(icon, color: color),

Container(

margin: const EdgeInsets.only(top: 8),

child: Text(

label,

style: TextStyle(

fontSize: 12,

fontWeight: FontWeight.w400,

color: color,

),

),

),

],

);

‫ كود فئتي الويدجيت‬.4.4


‫كود الفئة االولى‬ 
class FavoriteWidget extends StatefulWidget {

@override

_FavoriteWidgetState createState() => _FavoriteWidgetState();

‫كود الفئة الثانية‬ 


class _FavoriteWidgetState extends State<FavoriteWidget> {

bool _isFavorited = true;

int _favoriteCount = 41;

void _toggleFavorite() {

setState(() {

if (_isFavorited) {

_favoriteCount -= 1;

_isFavorited = false;

} else {

_favoriteCount += 1;

_isFavorited = true;

}); }

:‫داخل التطبيق يمكنك استدعاء الويدجيت باألمر التالي‬

FavoriteWidget)(

‫فتقوم بإظهار النجمة وعداد اإلعجاب في المكان الذي استدعيتها فيه وتنتظر من المستخدم أن ينقرعلى النجمة التي اظهرتها لتستجيب‬
‫له بتغيير شكلها وقيمة االعجاب‬
‫تمرين اختياري‬

‫يمكنك تعديل تطبيق البحيرة قليال حتى تشعر بالثقة بأنك قد بدأت بعمل تطبيقك الخاص‪.‬‬

‫غير الصورة‬ ‫‪‬‬


‫والشرح‬ ‫‪‬‬
‫والمظهر‬ ‫‪‬‬
‫وعنوان التطبيق‬ ‫‪‬‬
‫جرب استخدم نصوص عربية‬ ‫‪‬‬
‫هنالك خاصية في ويدجيت النص تغير االتجاه من اليمين للليسار ‪ rtl‬يمكنك استخدامها‬ ‫‪‬‬

‫المراجع‬
‫‪Adding interactivity to your Flutter app, https://flutter.dev/docs/development/ui/interactive‬‬

‫الرجوع جلدول احملتوايت‬


‫الباب التاسع‬

‫تصميم تطبيق من الصفر‬

‫‪main.dart‬‬
‫مقدمة‬

‫في هذا الباب سنستفيد من كل ما سبق لعمل تطبيق متكامل (ساكن)‪ ،‬بحيث نشرح كل خطوة فيه‬
‫ونبين شكل المخرج كيف سيكون في كل خطوة من هذه الخطوات‪.‬‬

‫سنستخدم كثيير من الويدجيتس بداية من اسكافولد وانتهاءا بويدجيتس التخطيط (التنسيث)‪،‬‬


‫وسنحرص على فهم كل االكواد التي تكون التطبيق‪ ،‬بحيث يصبح الشخص قادرا بنهاية هذا الباب‬
‫على تصميم تطبيقك الذي تريد‪ ،‬وبالشكل الذي يعجبك‪.‬‬

‫كل العمل هنا سيكون في ملف المشروع الرئيسي وهو ‪ ،main.dart‬وفد نحتاج الى تعديل‬
‫طفيف في ملف التهيئة ‪pubspec.yaml‬‬

‫صفات الويدجيتس‬

‫قبل البدء سنذكر ونستذكر صفات الويدجيتس التي تساعدنا في فهم االكواد‪.‬‬

‫من الصفات الهامة ما يلي‪:‬‬

‫‪ .1‬أي ودجيت هي فئة تحتوي على صفات (‪ )properties‬ودوال (‪)methods‬‬


‫‪ .2‬أي ودجيت تحتوي على داله إنشاء (‪ )constructor‬تقبل مدخالت ( ‪zero or more‬‬
‫‪. )parameters‬‬
‫‪ .3‬أي ودجيت يحتوي على الدالة (‪ )build‬والتي تستقبل (‪ )BuildContext‬وترجع‬
‫ودجيت واحدة (‪)returns a single Flutter widget‬‬

‫شجرة الودجيت (‪)widget tree‬‬

‫عرفنا أن كل شئ في فلتر عبارة عن ودجيت وهذا إلى حد كبير يبين أنها ليست سوى تسلسل‬ ‫‪‬‬
‫هرمي عمالق من الوديجيدتس (‪ )hierarchy of widgets‬وهذا التسلسل الهرمي يسمى في‬
‫فلتر ب "شجرة الودجيت" (‪.)widget tree‬‬
‫كما ترى ‪ ،‬فإن معظم الودجيدتس يمكن أن يكون لها ابن واحد أو أكثر (‪ . )childern‬ويمكن‬ ‫‪‬‬
‫أن يكون لكل ابن من هؤالء األبناء ابن واحد أو أكثر ‪ ،‬وهكذا‪.‬‬
‫جميع الوجيدتس عبارة عن فئات ‪ ، Dart‬وعادة يجب أن تحتوي على الدالة ()‪ build‬التي‬ ‫‪‬‬
‫ترجع هذه الدالة ودجيدتس أخرى (‪.)return other widgets‬‬
‫هناك بعض االستثناءات القليلة جدًا لهذا ‪ ،‬بعض الودجيدتس ذات المستوى المنخفض مثل‬ ‫‪‬‬
‫ودجيت النص (‪ )Text widget‬والتي تُرجع نو ً‬
‫عا بدائيًا (سلسلة (‪))string‬‬

‫النظر عن هذا المتطلب ‪ ،‬على مستوى الكود ‪ ،‬فإن الودجيت هو مجرد فئة ‪Dart‬‬ ‫بصر‬
‫ال تختل عن بقية الفئات في شئ‬
‫فئيتي فلتر ‪Stateless & Stateful Widget‬‬

‫ترث الويجيدتس عادة واحدا من الفئات القياسية التي توفرها فلتر ‪.‬‬

‫هنالك نوعان من الفئات القياسية التي نستخدمهما معظم الوقت وهما‪:‬‬

‫‪StatelessWidget ‬‬
‫‪StatefulWidget ‬‬

‫الودجيت الذي يرث ‪ StatelessWidget‬ال يتغير أبدًا(ساكن)‪ ،‬ويطلق عليه ‪stateless widget‬‬
‫ألنه حالته ال تتغير ‪.‬‬

‫كيف يتم إنشاء واجهات المستخدم (‪ )UI‬في فلتر‬

‫تستخدم دارت‬ ‫معلوم أن فلتر تستخدم لغة دارت (‪ )Dart‬في السلوك والتمثيل (الشكل)‪ ،‬السؤال هنا كي‬
‫في تصميم الشكل؟‪.‬‬

‫ليس هنالك اشكال جاهزة لالزرار والقوائم ومربعات النصوص وغيرها‪ ،‬وانما هنالك كود لكل شكل‬
‫يكتب بلغة دارات (كما رأينا في االبواب السابقة)‪,‬‬

‫فهم بداية التطبيق‬

‫يبدأ تطببق فلتر العمل من الدالة ‪main‬‬

‫‪ ‬تستدعي ‪ main‬دالة اخرى تسمى ‪runApp‬‬


‫‪ ‬تستلم الدالة (‪ )runApp‬كمدخل ودجيت واحد هو الودجيت الجذر (‪ ،)root widget‬جذر‬
‫شجرة الويدجيت‪.‬‬
‫‪ ‬صفات ويدجيت الجذر‬
‫‪ o‬يمكنك تسميته بأي اسم‬
‫‪ o‬يجب أن يكون فئة (‪)class‬‬
‫‪ o‬يجب أن يرث (‪ )extends‬صفات الفئة ‪( StatelessWidget‬وهي فئة تابعة‬
‫لفلتر)‬

‫مثال (‪)1‬‬

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

‫كود أول تطبيق‪:‬‬


‫تضمني حزمة فلرت ‪ material.dart‬اليت حنتاهجا يف الربانمج‬
‫ادلاةل ‪ main‬تس تدع ادلاةل ‪ runApp‬اليت تس تمل الودجيت اجلذر ‪MyApp‬‬
‫اإنشاء فئة الودجيت اجلذر اليت ترث صفات الودجيت ‪StatelessWidget‬‬

‫ادلاةل ‪ build‬تقبل ‪ BuildContext‬مكدخل وترجع ويدجيت واحدة‬


‫ترجع ادلاةل ‪ Build‬الويدجيت ‪MaterialApp‬‬
‫الويدجيت اساكفودل وهبا ‪ AppBar‬فارغ و ‪ body‬حستوس وسدجست واحدة‬

‫الودجيت ‪ Text‬تظهرر‪ Learn Flutter‬يف اجلسم (‪)body‬‬


‫هناية اساكفودل‬
‫هناية ‪MaterialApp‬‬
‫هناية ادلاةل ‪Build‬‬
‫هناية الويدجيت اجلذر ‪MyApp‬‬

‫المخرج‬

‫الصورة التالية هي نتيجة تنفيذ البرنامج اعاله‪ ،‬ونالحظ ان الشريط االزرق فارغ (‪ )AppBar‬الننا‬
‫لم نضع فيه عنوان‪ ،‬ايضا نالحظ ان العبارة ‪ Learn Flutter‬ظهرت في الركن االعلى االيسر‬
‫من الجسم (‪ ،)body‬ألننا لم نستخدم ويدجيت تنسييق مثل ‪Center‬‬
‫مثال (‪)2‬‬

‫التالي‪:‬‬ ‫االن سنعدل في البرنامج ونضي‬

‫عنوان في ‪AppBar‬‬

‫استخدام ويدجيت التوسيط (‪ )Center‬لجعل النص يظهر في وسط الجسم (‪)body‬‬

‫وسنستخدم اللغة العربية في كتابة النصوص‪.‬‬


‫;'‪import 'package:flutter/material.dart‬‬
‫;))(‪void main() => runApp(MyApp‬‬
‫{ ‪class MyApp extends StatelessWidget‬‬
‫‪@override‬‬
‫{ )‪Widget build(BuildContext context‬‬
‫(‪return MaterialApp‬‬
‫(‪home: Scaffold‬‬
‫‪//////////////////////////////////////////////‬‬
‫‪")),‬كتابي اكاديمية"(‪appBar: AppBar(title: Text‬‬
‫‪//////////////////////////////////////////////‬‬
‫‪body:‬‬
‫ت‬
‫‪ '),),‬فلتؤ علم'(‪Center(child: Text‬‬
‫‪),‬‬
‫;)‬
‫}‬
‫}‬

‫نالحظ ان اضافة عنوان في ‪ AppBar‬تم استخدام الويدجيت ‪Text‬‬

‫لتوسيط النص في ‪ body‬تم احاطته بويدجيت ‪Center‬‬

‫تنبيه هام‪ :‬اذا وضعت ويدجيت داخل ويدجيت البد من استخدام ‪ child‬لذلك‬
)3( ‫مثال‬

‫ في هذا المثال سنستخدم‬.‫ دون التعمق فيها‬،‫في االمثلة السابقة استخدمنا ويدجيت النص الظهار نص‬
‫ لتنسيق النص‬style
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
/////////////////////////////////////////////////////
appBar: AppBar(title: Text("‫))"كتابي اكاديمية‬,
/////////////////////////////////////////////////////
body:
Center(
child:
‫ت‬
Text( ' ‫' فلتر علم‬,
style: TextStyle(
fontSize: 48.0, // ‫حجم الخط‬
color: Colors.deepOrange, // ‫لون الخط‬
decoration: TextDecoration.underline, // ‫خط تحت النص‬
fontStyle: FontStyle.italic, // ‫خطا مائل‬
fontWeight: FontWeight.bold, // ‫خط عريض‬
),
),
),
),
);
}
}
‫المخرج‬

‫ غير من شكل الخط وحجمه ولونه‬TextStyle ‫نالحظ في هذا المثال ان استخدام‬


)4( ‫مثال‬

‫ فيكون الكود والمخرج كما يلي‬AppBarِ ‫ في‬leading ‫سنضيق قائمة‬


import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
///////////////////////////////////////////////////////
appBar: AppBar(title: Text("‫)"كتابي اكاديمية‬,
leading: IconButton(
icon: Icon(Icons.menu),
onPressed: () { },
),
),
////////////////////////////////////////////////////////
body:
Center(
child:
Text(
‫ت‬
' ‫' فلتر علم‬,
style: TextStyle(
fontSize: 48.0,
color: Colors.deepOrange,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.bold,
),
),
),
),
);
}
}
,decoration: TextDecoration.underline ‫تم ازالة السطر‬

‫ كما يظهر في الشكل التالي‬leading ‫ واضافة قائمة‬،‫ في تنسيق النص‬TextStyle ‫من‬


)5( ‫مثال‬

.‫ النص االول هو النص في المثال السابق مع تنسيقه‬،‫عمود نضع فيه ثالث نصوص‬ ‫سنضي‬
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("‫)"كتابي اكاديمية‬,
leading: IconButton(
icon: Icon(Icons.menu),
onPressed: () { },
),
),
////////////////////////////////////////////////////////////////
body:
Column(crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.
spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
‫ت‬
Text(' ‫' فلتر علم‬,
style: TextStyle(
fontSize: 48.0,
color: Colors.deepOrange,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.bold,
),
),
Text('‫)'عثمان عيدالرحمن‬,
Text(' ‫)' كتابي اكاديمية‬,
Padding(padding: EdgeInsets.all(16.0),),
],
),
),
);
}
}

‫المخرج‬

)5( ‫مثال‬

)play_arrow( ‫تعديل تنسيق النصوص في العمود واضافة زر عائم لتشغيل الميديا‬


import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
////////////////////////////////////////////////////////////
appBar: AppBar(title: Text("‫)"كتابي اكاديمية‬,
leading: IconButton(
icon: Icon(Icons.menu),
onPressed: () { },
),
),
/////////////////////////////////////////////////////////////
body:
Column(crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.
spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
‫ت‬
Text(' ‫' فلتر علم‬,
style: TextStyle(
fontSize: 48.0,
color: Colors.deepOrange,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.bold,
),
),
Text(' ‫' عثمان عيدالرحمن‬,
style: TextStyle(
fontSize: 48.0,
color: Colors.lightGreen,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.bold,
),
),
Text(' ‫' كتابي اكاديمية‬,
style: TextStyle(
fontSize: 48.0,
color: Colors.indigo,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.bold,
),
),
Padding(padding: EdgeInsets.all(16.0),),
],
),
////////////////////////////////////////////////////////////////////////////
floatingActionButtonLocation: FloatingActionButtonLocation.endDocked,
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.play_arrow),
backgroundColor: Colors.lightGreen.shade100,
),
),
);
}
}
‫المخرج‬

)6( ‫مثال‬

end :‫في ها المثال نم تعديل اتجاه خاليا العمود لليمين باستخام‬

)‫ لويدجيت النص الول خلية في العمود (تعلم فلتر‬textAlign: TextAlign.right ‫تم اضافة‬

backgroundColor: Colors.lightGreen.shade100 ‫تم تعطيل امر لون الخلفية للزر العائم‬

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("‫)"كتابي اكاديمية‬,
leading: IconButton(
icon: Icon(Icons.menu),
onPressed: () { },
),
),
body:
Column(crossAxisAlignment: CrossAxisAlignment.end,// ‫اظهار على اليمين‬
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
‫ت‬
Text(' ‫' فلتر علم‬,
textAlign: TextAlign.right, // ‫اتجاه النص‬
style: TextStyle(
fontSize: 48.0,
color: Colors.deepOrange,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.bold,
),
),
Text(' ‫' عثمان عيدالرحمن‬,
style: TextStyle(
fontSize: 48.0,
color: Colors.lightGreen,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.bold,
),
),
Text(' ‫' كتابي اكاديمية‬,
style: TextStyle(
fontSize: 48.0,
color: Colors.indigo,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.bold,
),
),
Padding(padding: EdgeInsets.all(16.0),),
],
),
floatingActionButtonLocation: FloatingActionButtonLocation.endDocked,
floatingActionButton: FloatingActionButton(
onPressed: () {print("playing ...");},
child: Icon(Icons.play_arrow),
// backgroundColor: Colors.lightGreen.shade100,// ‫تعطيل اللون‬

),
),
);
}
}

‫المخرج‬
‫مثال (‪)7‬‬

‫اضافة صورةمضمنة في العمود ‪:‬‬

‫الضافة صورة مضمنة ‪Ñ‬‬

‫‪ .1‬سننشئ مجلد داخل التطبيق (سميه )‪))img‬‬


‫‪ .2‬انسخ الصورة داخله (تسمها ‪)ka.png‬‬
‫‪ .3‬افتح المل (‪ )pubspec.yaml‬ثم اض اسم الصورة بمسارها تحت ‪ assets‬كما يلي‪:‬‬
‫‪assets:‬‬
‫‪- img/ka.png‬‬

‫‪ .4‬نكتب االمر التالي في التطبيق الظهار الصورة‪:‬‬


‫‪5. Image(image: AssetImage('images/ka.png'),‬‬
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("‫)"كتابي اكاديمية‬,
leading: IconButton(
icon: Icon(Icons.menu),
onPressed: () { },
),
),
body:
Column(crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
///////// 01
‫ع‬‫ت‬
Text(' ‫' فلتر لم‬,
textAlign: TextAlign.right,
style: TextStyle(
fontFamily: 'Arial',
fontSize: 32.0,
color: Colors.deepOrange,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.bold,
),
/////////// 02
),
Text(' ‫' عثمان عيدالرحمن‬,
style: TextStyle(
fontFamily: 'Andalus',
fontSize: 32.0,
color: Colors.lightGreen,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.bold,
),
),
/////////////// 03
Image(image: AssetImage('images/ka.png'),
),
],
),

////////////////////////////////////////////////////////////////////
floatingActionButtonLocation:
FloatingActionButtonLocation.endDocked,
floatingActionButton: FloatingActionButton(
onPressed: () {print("playing ...");},
child: Icon(Icons.play_arrow),
),
),
);
}
}

‫المخرج‬

:‫عند الضغط على الزر العائم تظهر رسالة في الكونسول كما يلي‬
‫مالحظة‬

‫تم تصغير حجم الخط الى ‪ 32‬من ‪44‬‬

‫تم اضافة اسم الخط كما يلي‪:‬‬

‫للنص االول (تعلم فلتر)‬

‫'‪fontFamily: 'Arial,‬‬

‫للنص الثاني (عبدالرحمن عثمان)‬

‫‪fontFamily: 'Andalus',‬‬

‫لكن لم يتغير شكل الخط !!!‬

‫الحل في المثال التالي‬


‫بغد البحث وجدنا انه ينكنك اذا اردت استخدام خطوط من خارج فلتر (مثل خطوط ويندوز او خطوط‬
‫قمت بتحميلها من االنترنت)‪ ،‬فعليك انشاء مجلد في تطبيقك ونسخ الخطوط التي تريد استخدامها فيه‪،‬‬
‫وتعري مكانها للتطلبق في المل ‪ ،pubspec.yaml‬ثم بعد ذلك استخدامها في التطبيق‪.‬‬

‫الخطوات‬

‫‪ ‬انشئ مجلد في تطبيقك سميه ‪( fonts‬يمكنك تسميه باي اسم)‬


‫‪ ‬اذهب الى مجلد الخطوط في جهازك (غندي في المسار ‪)C:\Windows\Fonts‬‬
‫‪ ‬انسخ الخطوط التي تريد‬
‫‪ ‬الصقها في المجلد الذي انشاته في التطبيق‬
‫‪ ‬افتح مل ‪ pubspec.yml‬وعدله بالخطوط التي تريد‬

‫‪ ‬سيكون التعديل كما يلي‪:‬‬

‫‪ ‬بعدها يمكنك اشتخدام الخطوط داخل تطبيقك باالسماء التي سميتها بعا في ‪pubspec.yaml‬‬
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("‫)"كتابي اكاديمية‬,
leading: IconButton(
icon: Icon(Icons.menu),
onPressed: () { },
),
),
body:
Column(crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
///////// 01
‫ع‬‫ت‬
Text(' ‫' فلتر لم‬,
textAlign: TextAlign.right,
style: TextStyle(
fontFamily: 'Andalus1',
fontSize: 62.0,
color: Colors.deepOrange,
),
/////////// 02
),
Text(' ‫' عثمان عيدالرحمن‬,
style: TextStyle(
fontFamily: 'Andalus1',
fontSize: 62.0,
color: Colors.lightGreen,
),
),
/////////////// 03
Image(image: AssetImage('images/ka.png'),
),
],
),
////////////////////////////////////////////////////////////////////
floatingActionButtonLocation: FloatingActionButtonLocation.endDocked,
floatingActionButton: FloatingActionButton(
onPressed: () {print("playing ...");},
child: Icon(Icons.play_arrow),
),
),
);
}
}
‫المخرج‬

‫تم تغيير حجم الخط الى ‪ ،22‬واستخدام الخط الجديد الذي وضعه في التطبيق (وهو االندلس) وتم تسميته‬
‫‪ Andalus1‬في المل ‪pubspec.taml.‬‬

‫تنبيه‬

‫يمكنك تحميل خطوط من االنترنت واستخدامها بنفس الطريقة‪.‬‬

‫المراجع‬
‫‪Beginning Flutter, a hands on guide to app development, Marco L.‬‬
‫‪Napoli, 2020, Wiley & Sons, Inc.‬‬

‫الرجوع جلدول احملتوايت‬


‫الباب العاشر‬

‫ويدجيت النموذج‬

‫‪Form Widget‬‬
‫‪ .1..1 .1‬ويدجيت النموذج (‪)Form‬‬
‫جميع‬ ‫ويدجيت النموذج هو ويدجيت غير مرئي‪ .‬هذا يعني أنك لن تراه أبدًا‪ .‬والغرض الوحيد منه هو التفا‬

‫مدخالته ‪ ،‬وبالتالي تجميعها ‪ -‬وبياناتها ‪ -‬في وحدة واحدة‪ .‬يفعل ذلك باستخدام مفتاح (إذا قررت استخدام نموذج ‪ ،‬فأنت‬
‫بحاجة إلى مفتاح عالمي (‪ GlobalKey‬من النوع ‪)) FormState‬‬

‫مفتاح كما يلي‬ ‫لذلك علينا في البداية تعري‬

‫;)(>‪GlobalKey<FormState> _key = GlobalKey<FormState‬‬

‫ثم اضف هذا المفتاح كخاصية نموذجك كما يلي‪:‬‬

‫(‪Form‬‬
‫مفتاح النموذج ‪key: _key, //‬‬
‫التحقق االوتوماتيكي مفعل ‪autovalidate: true, //‬‬
‫تضيف هنا حقول النموذج ‪child: //‬‬
‫‪),‬‬
‫‪),‬‬

‫خصائص النموذج‬
‫تاحذ ‪ utovalidate‬فيمة منطقية‪ ،‬اذا كانت ‪ True‬تعني ان التحقق شغال ويعمل مع اي تغيير يحدث في‬
‫اي حقل من حقول المنوذج‪ ،‬اذا كانت ‪ ، False‬فهذا يعني انه عليك القيام بالتحقق يدويا (بكود تكتبه انت)‬

‫المفتاح (سميناه ‪ _key‬في المثال السابق)‪ ،‬لديه خاصية ‪ currentState‬التي لديها الدوال التالية‬

‫‪ : save() .1‬يحفظ جميع الحقول التي بداخل النموذج عن طريق استدعاء ‪ onSaved‬كل حقل‬
‫(لكل حقل ‪ onSaved‬خاصة به)‬
‫‪ : validate() .0‬تنفيذ الدالة ‪ validator‬لكل حقل (حبث يحتوي كل حقل على ‪validator‬‬
‫خاصة به)‬
‫‪ :reset() .3‬إعادة تعيين كل حقل داخل النموذج إلى القيمة األولية الخاصة به‬

‫مهمة النموذج هي تجميع الحقول التي بداخله لتعمل معا‪.‬‬

‫عند استدعاء إحدى هذه الدوال الثالثة اعاله على ‪ ، FormState‬فإنه يكرر الحقول الداخلية ويستدعي‬
‫تلك الدوال في كل منها‪ .‬استدعاء واحد على مستوى النموذج يشغلها كلها ‪.‬‬

‫االمر‪:‬‬

‫)(‪If _key.currentState.save‬‬
‫ للحقل‬.validator ‫ تستدعاء‬validate() ‫ بنفس الطريقة فان‬، ‫ للحقل‬onSaved ‫يستدعي‬

‫ ال تمتلك هذه‬Slider ‫ و‬Checkbox ‫ و‬Radio ‫ و‬Dropdown ‫ و‬TextField ‫الويدجيتس‬


‫ ماذا نفعل االن؟‬.‫األساليب‬
‫ الذي يحتوي على هذه األساليب‬FormField ‫نضع (نغلف) كل حقل في ويدجيت‬

FormField ‫ الويدجيت‬.1..1

‫) والتحقق من صحة‬reset( ‫) وإعادة التعيين‬save( ‫الغرض االساسي لهذه الويدجيت هو توفير الحفظ‬
.‫)) االحداث للويدجيت الداخلية‬validator((

:builder ‫ مع‬FormField ‫نستخدم الويدجيت‬ ‫كود يوضح كي‬.


FormField<String>(
builder: (FormFieldState<String> state) {
return TextField(); // Any field widget like DropDownButton,
// Radio, Checkbox, or Slider.
},
onSaved: (String initialValue) {
// Push values to a repository or something here.
},
validator: (String val) {
// Put validation logic here
},
),

builder ‫أي ويدجيت باستخدام خاصية‬ ‫ التفا‬FormField ‫يمكن للويدجيت‬

‫ ويتم ذلك عن طريق دالة‬،‫ ليلت (بغا ) ويدجيت االدخال‬FormField ‫لقد استخدمنا‬
validator ‫ والدالة‬onSaved ‫ ثم بعدها يمكننا اضافة الدالة‬، builder ‫تسمى‬

)1( ‫مثال‬

.‫في المثال التالي سننشئ نموذج يحتوي على حقل واحد الدخال اسم‬
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
GlobalKey<FormState> _key = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
//////////////////////////////////////////////
appBar: AppBar(title: Text("‫)"كتابي اكاديمية‬,
centerTitle: true,
),
//////////////////////////////////////////////
body:
Form(
key: _key,
autovalidate: true,
child: FormField<String>(
builder: (FormFieldState<String> state) {
return TextField(); // Any field widget like DropDownButton,
// Radio, Checkbox, or Slider.
},
onSaved: (String initialValue) {
// Push values to a repository or something here.
},
validator: (String val) {
// Put validation logic here
},
),
),
),
);
}
}

‫المخرج‬

:‫ السطر التالي‬AppBar ‫ اصبح في الوسط الننا اضفنا في‬AppBar ‫تالحظ في المخرج ان العنوان في‬
centerTitle: true,

‫ سيظهر لك الكيبورد ويمكنك اذخال‬،‫اذا نقرت بالماوس على حقل النموذج الذي يظهر في الشكل اعاله‬
soft (‫بيانات في الحقل (باستخدام الكيبورد العادي او باستخدام الكيبورد الذي ظهر لك في شاشة التطبيق‬
:‫ كما يلي‬،))keyboard
‫التعامل مع ‪ TextField‬بشكل مختل ‪ .‬بدالً من لفه ‪ ،‬استبدله بالويدجيت ‪ TextFormField‬إذا كنت‬
‫تستخدمه داخل نموذج‪ .‬من السهل الخلط بين هذه الويدجيت مع ‪ TextField‬ولكنها مختلفة‪ .‬في األساس‬

‫‪TextFormField = TextField + FormField‬‬

‫علم فريق ‪ Flutter‬أننا سنحتاج بشكل روتيني إلى عنصر واجهة مستخدم ‪ TextField‬باالشتراك مع‬
‫عنصر واجهة مستخدم ‪ FormField‬لذلك قاموا بإنشاء ةيدجيت ‪ TextFormField‬الذي يحتوي على‬
‫جميع خصائص ‪ TextField‬ولكن يضي لها ‪ ، validator ،onsaved‬و ‪reset‬‬

‫مثال (‪)1‬‬

‫سنستخدم في عذا المثال ويدجيت ‪ TextFormField‬الذي يمتلك كل صفات الويدجيت ‪،TextField‬‬


‫باالضافة الى ‪ ، validator ، onsaved‬و ‪reset‬‬
‫(‪TextFormField‬‬
‫{ )‪onSaved: (String val‬‬
‫;)'‪print('Search Term TextField: form saved $val‬‬
‫‪},‬‬
‫{ )‪validator: (String val‬‬
‫‪// Put your validation logic here‬‬
‫‪},‬‬
‫‪),‬‬

‫هذا المثال سيعمل كمالثال السابق‪ ،‬ولكن هنا الكود مختصر‪ ،‬ويفضل استخدام هذا الويدجبت بدال من‬
‫‪ ،TextField‬النك في ‪ TextField‬ستحتاج الى استخدام ‪ FormField‬معه وكذلك الدالة ‪Build‬‬
‫الضافة ‪ ، validator ،onsaved‬و ‪ reset‬له‪.‬‬

‫اذن سنستخدم في بقية االمثلة الويدجيت ‪ TextFormField‬مع النماذج‪ ،‬وننصح بذلك ما لم‬
‫يكن هنالك شئ يجبرك على استخدام ‪TextField‬‬

‫الدالة ‪:onSaved‬‬

‫يرجى تذكر أن النموذج الخاص بك يحتوي على مفتاح يحتوي على ‪ currentState‬التي تحتوي على‬
‫الدالة )(‪ ، save‬مثال‬
‫();‪_key.currentState.save‬‬

‫ويستدعي بدوره الدالة ‪ onSaved‬لكل ‪ FormField‬يحتوي على واحدة (لكل الحقول التي في‬
‫النموذج)‬

‫المدقق (‪)validator‬‬

‫وبالمثل ‪ ،‬ربما خمنت أنه يمكنك استدعاء ;)(‪key.currentState.validate‬‬

‫‪ ...‬وسيستدعي فلتر دالة التحقق ‪ validator‬لكل ‪.FormField‬‬

‫ولكن هناك المزيد! إذا قمت بتعيين خاصية التحقق التلقائي للنموذج (‪ )autovalidate‬إلى ‪، true‬‬
‫فورا عندما يقوم المستخدم بإجراء التغييرات‪.‬‬
‫فسيتحقق فلتر من الصحة ً‬
.)string( ‫نص‬/‫ وترجع سلسلة‬- ‫ القيمة المطلوب التحقق منها‬- ‫ قيمة‬validator ‫ستتلقى كل دالة‬
‫) إذا كانت قيمة اإلدخال صحيحة وستكون القيمة المدخلة إذا‬null( ‫ستكون القيمة المرجعة قيمة خالية‬
.‫ هذه السلسلة التي تم إرجاعها هي رسالة الخطأ التي سيظهرها فلتر للمستخدم‬.‫كانت غير صحيحة‬

)Validate while typing( ‫تحقق أثناء الكتابة‬

.‫تذكر أن طريقة إجراء التحقق الفوري هي تعيين النموذج‬

‫) لـ‬validator( ‫وكتابة مدقق‬ )true ( ‫) مفعال‬autovalidate( ‫حيث يتم جعل التحقق التلقائي‬
:‫ الخاص بك‬TextFormField
return Form(
autovalidate: true,
child: Container(
TextFormField(
validator: (String val) { // Let's say that an empty value is invalid.
if (val.isEmpty)
return 'We need something to search for';
return null;
},
),
),
);

‫مثال‬

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
GlobalKey<FormState> _key = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
//////////////////////////////////////////////
appBar: AppBar(title: Text("‫)"كتابي اكاديمية‬,
centerTitle: true,
),
//////////////////////////////////////////////
body:
Form(
key: _key,
autovalidate: true,
child: TextFormField(
onSaved: (String val) {
print('Search Term TextField: form saved $val');
},
validator: (String val) {
if (val.isEmpty)
return 'We need something to search for';
return null;// Put your validation logic here
},
),
),
),
);
}
}

‫المخرج‬

‫ أو‬DropdownButton ‫ زر‬:‫من الواضح أنه ليس من المنطقي التحقق من الصحة للويدجيتس التالية‬
.‫ الننا ال تكتب شئ فيها‬Slider ‫ أو‬Switch ‫ أو‬Checkbox ‫ أو‬Radio
.TextFormField ‫ يعمل فقط مع‬.FormField ‫ داخل‬TextField ‫ولكنه ال يعمل مع‬

‫ داخل‬TextField ‫ ولكن إذا كنت تصرعلى استخدام‬.TextFormField ‫نصيحة من االفضل استخدام‬


:‫ يمكنك القيام بذلك بطريقة مثل هذه‬، FormField
FormField<String>(
builder: (FormFieldState<String> state) {
return TextField(
controller: _emailController,
decoration: InputDecoration(
// This says if the value looks like an email set errorText
// to null. If not, display an error message.
errorText:
RegExp(r'^[a-zA-Z0-9.]+@[a-zA-Z0-9]+\.[a-zA-Z]+')
.hasMatch(_emailController.text)
? null

submit ‫التحثث من المخالت بعد الضغط على زر‬

‫ عند‬،‫تحيانا تحتاج كتابة كود اختبار المدخالت والتحقق من صحتها بعد االنتهاء من ادخال كل البيانات‬
:‫ للقيام بذلك تحتاج‬،)submit( ‫الضغط على ور موافق‬

)‫ فيها‬false ‫ (وضع قيمة‬autovalidate ‫ تعطيل‬.1


:‫) كما يلي‬submit( ‫ عند الضغط على زر موافق‬onPressed ‫ في‬validate() ‫ استدعاء‬.0

RaisedButton(
child: const Text('Submit'),
onPressed: () {
// If every field passes validation, run their save methods.
if (_key.currentState.validate()) {
_key.currentState.save();
print('Successfully saved the state.');
}
},
),

3 ‫مثال‬

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
GlobalKey<FormState> _key = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
//////////////////////////////////////////////////////////////

appBar: AppBar(title: Text("‫)"كتابي اكاديمية‬,


centerTitle: true,
),
//////////////////////////////////////////////////////////////
body:
Container(
child: Form(
key: _key,
autovalidate:false,
child: Column(children: <Widget>[
TextFormField(
onSaved: (String val) {
print('Search Term TextField: form saved $val');
},
/*validator: (String val) {
// Put your validation logic here
},*/

),
//////////////////////////////////////////////////////////////

RaisedButton(
child: const Text('Submit'),
onPressed: () {
// If every field passes validation, run their save methods.
if (_key.currentState.validate()) {
_key.currentState.save();
print('Successfully saved the state.');
}
},
),
],
),
),
),
),
);
}
}

‫المخرج‬
‫مثال‬

:‫تم اصافة التعديالت التالية على كود المثال السابق‬

‫ في الحقل لتنبيه المستخدم ان عليه ادخال اسم هنا‬Name ‫ الظهار كلمة‬decoration 


‫ لتحديد نوع الكيبورد المناسب لالدخال‬keyboardType 
‫ بها كود يتحقق من االسم المدخل ان ال يقل طوله عن حرفين‬validator ‫ الدالة‬

TextFormField(
decoration: const InputDecoration(labelText: 'Name'),
keyboardType: TextInputType.text,
onSaved: (String val) {
print('Search Term TextField: form saved $val');
},
validator: (value) {
if (value.length < 2) {
return 'Name not long enough';
}
return null;
}
),

)main.dart( ‫الكود كامل‬


import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
GlobalKey<FormState> _key = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
//////////////////////////////////////////////
‫ت‬
appBar: AppBar(title: Text(" ‫)"فلتر علم كتاب‬,
centerTitle: true,
),
//////////////////////////////////////////////
body:
Container(
child: Form(
key: _key,
autovalidate:false,
child: Column(children: <Widget>[
TextFormField(
decoration: const InputDecoration(labelText: 'Name'),
keyboardType: TextInputType.text,
onSaved: (String val) {
print('Search Term TextField: form saved $val');
},
validator: (value) {
if (value.length < 2) {
return 'Name not long enough';
}
return null;
}
),
//////////////////////////////////////////////////////////////////////////
RaisedButton(
child: const Text('Submit'),
onPressed: () {
// If every field passes validation, run their save
methods.
if (_key.currentState.validate()) {
_key.currentState.save();
print('Successfully saved the state.');
}
},
‫‪),‬‬
‫‪],‬‬
‫‪),‬‬
‫‪),‬‬
‫‪),‬‬
‫‪),‬‬
‫;)‬
‫}‬
‫}‬

‫المخرج‬

‫نالحظ اذا ادخلنا اسم اقل من حرفين او لم ندخل اسم ستعمل الدالة ‪ validator‬التس ستختبر طول االسم‬
‫‪ ،‬اذا كان اقل من حرفين ستؤجع لنا رسالة خطا‪ ،‬كما يظهر في المخرج ادناه‪,‬‬

‫مثال‬

‫اضافة حقل الدخال رم الموبايل للبرنامج السابق‬

‫تطعر رسالة خطأ اذا لم تدخل رقم التلفون ()‪)if (potentialNumber == null‬‬

‫ستكون الرسالة ‪Enter a phone number‬‬

‫ما يدخله المستخدم سيتم وضعه في المتغير ‪ potentialNumber‬باالمر‬

‫;)‪var potentialNumber = int.tryParse(value‬‬


‫ الن البيانات التي يدخلها‬،‫ لتحويل المدخل الى عدد‬int.tryParse(value) ‫استخدمنا‬
‫المستخدم هنا ستكون نصية‬
TextFormField(
decoration: const InputDecoration(labelText: 'Mobile'),
keyboardType: TextInputType.phone,
validator: (value) {
var potentialNumber = int.tryParse(value);
if (potentialNumber == null) {
return 'Enter a phone number';
}
return null;
},
),

‫المخرج‬
‫استخدام حزمة ‪ mailValidator‬للتحقق من صحة االيميل‬

‫للتحفف من ان االيميل قد تم ادخاله بصورة صحيحة‪ ،‬يمكنك استخدام حزمة ‪mailValidator‬‬

‫اضف الحزمة (‪ )dependency package‬في ملف ‪ pubspec.yaml‬بالتطبيق كما يلي‪:‬‬


‫‪dependencies:‬‬

‫'‪email_validator: '^1.0.0‬‬
:main.dart ‫اضف االمر التالي في بداية‬
import 'package:email_validator/email_validator.dart';

:‫ مثال‬،‫ داخل البرنامج‬mailValidator ‫استخدم‬


TextFormField(
decoration: const InputDecoration(labelText: 'Email'),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (!EmailValidator.validate(value)) {
return 'Please enter a valid email';
}
return null;
},
),
‫قم بالموافقة وانت متصل باالنترنت‪.‬‬

‫عندما تبدا بتنفيذ البرنامج سيظهر لك فلتر ان هنالك حزمة (‪ )dependicies‬يجب تحميلها‬

‫مثال‬

‫في المثال التالي تم اضاف حقل الدخال االيميل والتحقق من صحته باستخدام حزمة‬
‫‪mailValidator‬‬

‫البرنامج كامل (يحتوي نموذج به ثالث حقول (االسم – التلفون – االيميل) وكل حقل يستخدم كيبورد‬
‫مخصص لالدخال‪ ،‬وبع خاصية التحقق من االدخال‬
‫;'‪import 'package:flutter/material.dart‬‬
‫;'‪import 'package:email_validator/email_validator.dart‬‬
‫;))(‪void main() => runApp(MyApp‬‬
‫{ ‪class MyApp extends StatelessWidget‬‬
‫;)(>‪GlobalKey<FormState> _key = GlobalKey<FormState‬‬
‫;‪String _name‬‬
‫‪@override‬‬
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
//////////////////////////////////////////////
‫ت‬
appBar: AppBar(title: Text(" ‫)"فلتر علم كتاب‬,
centerTitle: true,
),
//////////////////////////////////////////////
body:
Container(
child: Form(
key: _key,
autovalidate:false,
child: Column(children: <Widget>[
TextFormField(
decoration: const InputDecoration(labelText: 'Name'),
keyboardType: TextInputType.text,
onSaved: (String val) {
_name = val;
print('Search Term TextField: form saved $val'+ _name);
},
validator: (value) {
if (value.length < 2) {
return 'Name not long enough';
}
return null;
}
),
///////////////////////////////////////////////
TextFormField(
decoration: const InputDecoration(labelText: 'Mobile'),
keyboardType: TextInputType.phone,
validator: (value) {
var potentialNumber = int.tryParse(value);
if (potentialNumber == null) {
return 'Enter a phone number';
}
return null;
},
),
//////////////////////////////////////////////////////////////
TextFormField(
decoration: const InputDecoration(labelText: 'Email'),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (!EmailValidator.validate(value)) {
return 'Please enter a valid email';
}
return null;
},
),

///////////////////////////////////////////////////////////////
RaisedButton(
child: const Text('Submit'),
onPressed: () {
// If every field passes validation, run their save methods.
‫{ ))(‪if (_key.currentState.validate‬‬
‫;)(‪_key.currentState.save‬‬
‫;)'‪print('Successfully saved the state.‬‬
‫}‬
‫‪},‬‬
‫‪),‬‬
‫‪],‬‬
‫‪),‬‬
‫‪),‬‬
‫‪),‬‬
‫‪),‬‬
‫;)‬
‫}‬
‫}‬

‫لبمخرج‬

‫عند الضغط على االسم سيظهر لك الكيبورد المناسب وسيتم التحقق من االسم‪ ،‬اذا كان فارغا او اقل من‬
‫حرفين ستظهر لك رسالة خطأ‬
‫عند الضغط على حقل التلفون سيظهر لك كيبورد لالرقام فقط زاذا لم تدخل رقم تلفون ستظهر رسالة‬
‫خطأ‬
‫عند الشغط على حقل االيميل سيظهر كيبورد مناسب الدخال االيميل به عالمة (@) ‪ ،‬واذا لم تدخل ايميل‬
‫صحيح ستظهر لك رسالة خطأ‬
‫المراجع‬

 Beginning App Development with Flutter, Create Cross-Platform Mobile Apps, Rap Payne, 2019
 How to Make Email Validation in Flutter – Using Email Validator Library, Rajat
Palankar , March 18, 2020, https://protocoderspoint.com/email-validation-in-flutter-
using-email-validator-library/

‫الرجوع جلدول احملتوايت‬

You might also like