تعاملنا في الدروس السابقة مع عنصر واحد فقط يظهر على الشاشة. كان هذا العنصر عبارة عن لصيقة Label نُسندها إلى الخاصيّة Content
لصفحة محتوى content page. في البرامج الحقيقية كما هو معروف، سنحتاج بالتأكيد إلى العديد من العناصر التي ستظهر على الشاشة لتلبية متطلّبات البرنامج. المشكلة التي تصادفنا هنا أنّ الخاصية Content لصفحة المحتوى لا تقبل سوى عنصر واحد يرث من الصنف View
.
أوجدت Xamarin حلًا بسيطًا لهذه المشكلة يتمثّل في استخدام المخطّطات layouts. يمكن لأيّ مخطّط أن يستوعب أي عدد من العناصر التي يرث كل منها من الصنف View
. في الحقيقة يُعتبر المخطّط بحدّ ذاته يرث من الصنف Layout<View>
وهذا الصنف بدوره يرث بشكل غير مباشر من الصنف View
. لذلك يمكن إسناد أيّ مخطط للخاصية Content مباشرةً. تدعم Xamarin أربعة أنواع من المخطّطات وهي:
- المخطّط المطلق AbsoluteLayout
- مخطّط الشبكة GridLayout
- المخطّط النسبي RelativeLayout
- مخطّط المكدّس StackLayout.
سنتناول ثلاثة مخطّطات في هذه السلسلة وهي: المطلق والشبكي والمكدّس. وسنبدأ في هذا المقال بمخطّط المكدّس StackLayout.
مخطّط المكدّس StackLayout
يمكن إضافة أي عدد من العناصر إلى هذا المخطّط. وسبب تسميته بهذا الاسم هو أنّه يرتّب العناصر المضافة إليه بشكل متكدّس stacked. يمتلك الصنف StackLayout
خاصيتين إضافيتين عن باقي المخطّطات هما: Orientation
وتُعبّر عن الاتجاه (أفقي أو رأسي) وSpacing
وتمثّل التباعد بين العناصر المُضافة إلى المخطّط ولها القيمة الافتراضيّة 6.0
. لنتناول الآن مثال بسيط يوضّح آلية التعامل مع هذا المخطّط المفيد.
تطبيق ColorsApp لعرض بعض الألوان
أنشئ تطبيقًا جديدًا كما تعلّمنا من الدروس السابقة بحيث يكون من النوع Blank App (Xamarin.Forms Portable)
وسمّه ColorsApp
. بعد إنشاء التطبيق في Visual Studio أبق فقط على المشروعين ColorsApp (Portable)
و ColorsApp.Droid
.
أضف إلى المشروع ColorsApp (Portable)
صفحة محتوى سمّها ColorsListPage
(انقر بزر الفأرة الأيمن على المشروع واختر Add ثم اختر New Item. وبعد ظهور النافذة، اختر من الجهة اليسرى Cross-Platform، ومن وسط الشاشة اختر Forms ContentPage). بعد إنشاء هذه الصفحة سنلاحظ أنّها تحتوي بالفعل على مخطّط مكدّس جاهز. انظر إلى محتويات هذه الصفحة:
using System; using System.Collections.Generic; using System.Linq; using System.Reflection.Emit; using System.Text; using Xamarin.Forms; namespace ColorsApp { public class ColorsListPage : ContentPage { public ColorsListPage() { Content = new StackLayout { Children = { new Label { Text = "Hello ContentPage" } }, }; } } }
لاحظ كيف أنّنا نُسند كائنًا جديدًا من الصنف StackLayout إلى الخاصيّة Content ضمن البانية ColorsListPage. لاحظ أيضّا كيف أنّ المخطّط StackLayout يحتوي على خاصيّة اسمها Children تُعبّر عن العناصر الأبناء (كلّ منها يرث من الصنف View) التي نرغب بإضافتها إلى المكدّس. استبدل محتويات الملف ColorsListPage.cs بالشيفرة التالية:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Reflection.Emit; 5 using System.Text; 6 7 using Xamarin.Forms; 8 9 namespace ColorsApp 10 { 11 public class ColorInfo 12 { 13 public Color Color { get; set; } 14 public string Name { get; set; } 15 } 16 17 public class ColorsListPage : ContentPage 18 { 19 public ColorsListPage() 20 { 21 ColorInfo[] colors = new ColorInfo[] 22 { 23 new ColorInfo {Color= Color.Aqua,Name = "Aqua" }, 24 new ColorInfo {Color=Color.Blue,Name ="Blue" }, 25 new ColorInfo {Color=Color.Gray,Name ="Gray" }, 26 new ColorInfo {Color=Color.Black,Name ="Black" }, 27 new ColorInfo {Color=Color.Silver,Name ="Silver" }, 28 new ColorInfo {Color=Color.Red,Name ="Red" }, 29 new ColorInfo {Color=Color.Maroon,Name ="Maroon" }, 30 new ColorInfo {Color=Color.Yellow,Name ="Yellow" }, 31 new ColorInfo {Color=Color.Olive,Name ="Olive" }, 32 new ColorInfo {Color=Color.Lime,Name ="Lime" }, 33 new ColorInfo {Color=Color.Green,Name ="Green" }, 34 new ColorInfo {Color=Color.Navy,Name ="Navy" }, 35 new ColorInfo {Color=Color.Teal,Name ="Teal" }, 36 new ColorInfo {Color=Color.Pink,Name ="Pink" }, 37 new ColorInfo {Color=Color.Fuchsia,Name ="Fuchsia" }, 38 new ColorInfo {Color=Color.Purple,Name ="Purple" } 39 }; 40 41 StackLayout stackLayout = new StackLayout(); 42 43 for (int i = 0; i < colors.Length; i++) 44 { 45 stackLayout.Children.Add(new Label 46 { 47 Text = colors[i].Name, 48 TextColor = colors[i].Color, 49 FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)) 50 }); 51 } 52 53 Padding = new Thickness(5, 5, 5, 5); 54 55 Content = stackLayout; 56 } 57 } 58 }
لقد أضفنا صنفًا بسيطًا جديدًا اسمه ColorInfo
إلى هذا الملف (الأسطر من 11 حتى 15). ورغم أنّ وجود صنفين في نفس الملف هو عادة برمجيّة سيئة، إلّا أنّني آثرت ذلك طلبًا للتبسيط. تنحصر وظيفة هذا الصنف في الاحتفاظ بمعلومات بسيطة عن أيّ: قيمة اللون Color
واسمه Name
. أنشأنا في السطر 21 مصفوفة من الصنف ColorInfo
وأسندناها إلى المتغيّر colors
. ستحتوي هذه المصفوفة كما هو واضح على 16 لون. ننشئ بعد ذلك كائن جديد من الصنف StackLayout
ونسنده إلى المتغيّر stackLayout
(السطر 41)، ثم ندخل حلقة for
(السطر 43) وظيفتها المرور على عناصر المصفوفة colors
، وبحيث تُنشئ في كل دورة لصيقة Label جديدة وتُعيّن لها النص ولونه وحجمه، وتضيف هذه اللصيقة مباشرةً إلى مخطّط المكدّس stackLayout
عن طريق التابع Add
للخاصيّة Children
منه. بعد ذلك نُحدّد مقدار الحشوة padding
للصفحة (السطر 53) وفي النهاية نُسند المتغيّر stackLayout
إلى الخاصية Content
للصفحة (السطر 55). لتجربة هذا التطبيق، انتقل أولًا إلى الملف App.cs
واحرص أن تكون بانية الصنف App
على الشكل التالي:
public App() { // The root page of your application MainPage = new ColorsListPage(); }
نفّذ البرنامج باستخدام F5 لتحصل على شكل شبيه بما يلي:
نلاحظ هنا أمرين مهمّين. الأوّل أنّ بعض الألوان لا تظهر بشكل جيّد على الخلفية السوداء (وهي الخلفية الافتراضية لتطبيقات Xamarin في أندرويد) لأنّ التباين اللوني ليس جيّدًا، بل إنّ الكلمة Black
لن تظهر لأنّ لونها يماثل لون الخلفية الأسود. أمّا الأمر الثاني، فلدينا بالأساس 16 لون إلّا أنّه ظهر 12 لون منها فقط. من الممكن أن يختلف عدد الألوان الظاهرة عندك بحسب الشاشة التي تستخدمها، فقد تظهر جميعها مثلًا، ولكن على كلّ الأحوال ستواجه بالتأكيد تطبيقات في المستقبل لن تظهر فيها جميع العناصر دفعةً واحدة على الشاشة. في الواقع نحتاج إلى آلية لتمرير المحتويات scrolling
مثل أيّ تطبيق أندرويد آخر. سنعالج الآن كلًّا من الأمرين السابقين.
تطبيق ColorsApp المحسّن
سنعالج في البداية مسألة التباين اللوني التي من الممكن حلّها بإضافة تابع جديد إلى الصنف ColorsListPage
واسمه GetSuitableBackground
. تنحصر وظيفة هذا التابع بحساب مقدار الإنارة luminance
وفق ثوابت عدديّة متعارف عليها على أنّها مثالية. فإذا كانت الإنارة للّون المراد إظهاره أكبر من 0.5 فستكون الخلفية سوداء، أمّا إذا كانت أقل من أو تساوي 0.5 فستكون الخلفية بيضاء. مما يمنح تباينًا مناسبًا لعرض الألوان على الشاشة. انظر الشيفرة البرمجيّة الخاصّة بهذا التابع:
private Color GetSuitableBackground(Color color) { double luminance = 0.30 * color.R + 0.59 * color.G + 0.11 * color.B; return luminance > 0.5 ? Color.Black : Color.White; }
تُعبّر الخصائص color.R
و color.G
و color.B
عن المكوّنات الأحمر والأخضر والأزرق على الترتيب للّون الممرّر لهذا التابع والمراد إيجاد لون الخلفية المناسب له. أمّا الثوابت 0.30
و 0.59
و 0.11
فهي ثوابت تُعتبر مثالية لإيجاد إنارة اللون ويمكنك تغييرها إذا أحببت.
أمّا بالنسبة لمسألة تمرير محتويات الشاشة فحلّها بسيط، ويتمثّل في استخدام الصنف ScrollView
حيث نُنشئ كائن جديد منه، ونُسند المتغيّر stackLayout
إلى الخاصيّة Content
من ذلك الكائن، ثم نُسند ذلك الكائن الجديد إلى الخاصيّة Content
لصفحة المحتوى ColorsListPage
بدلًا من إسناد stackLayout
مباشرةً إليها كما كنّا نفعل في البرنامج السابق. انظر إلى الشيفرة التالية:
Content = new ScrollView { Content = stackLayout };
انظر الآن إلى الشيفرة الكاملة بعد إجراء التعديلات السابقة عليها:
using System; using System.Collections.Generic; using System.Linq; using System.Reflection.Emit; using System.Text; using Xamarin.Forms; namespace ColorsApp { public class ColorInfo { public Color Color { get; set; } public string Name { get; set; } } public class ColorsListPage : ContentPage { public ColorsListPage() { ColorInfo[] colors = new ColorInfo[] { new ColorInfo {Color= Color.Aqua,Name = "Aqua" }, new ColorInfo {Color=Color.Blue,Name ="Blue" }, new ColorInfo {Color=Color.Gray,Name ="Gray" }, new ColorInfo {Color=Color.Black,Name ="Black" }, new ColorInfo {Color=Color.Silver,Name ="Silver" }, new ColorInfo {Color=Color.Red,Name ="Red" }, new ColorInfo {Color=Color.Maroon,Name ="Maroon" }, new ColorInfo {Color=Color.Yellow,Name ="Yellow" }, new ColorInfo {Color=Color.Olive,Name ="Olive" }, new ColorInfo {Color=Color.Lime,Name ="Lime" }, new ColorInfo {Color=Color.Green,Name ="Green" }, new ColorInfo {Color=Color.Navy,Name ="Navy" }, new ColorInfo {Color=Color.Teal,Name ="Teal" }, new ColorInfo {Color=Color.Pink,Name ="Pink" }, new ColorInfo {Color=Color.Fuchsia,Name ="Fuchsia" }, new ColorInfo {Color=Color.Purple,Name ="Purple" } }; StackLayout stackLayout = new StackLayout(); for (int i = 0; i < colors.Length; i++) { stackLayout.Children.Add(new Label { Text = colors[i].Name, TextColor = colors[i].Color, BackgroundColor = GetSuitableBackground(colors[i].Color), FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)) }); } Padding = new Thickness(5, 5, 5, 5); Content = new ScrollView { Content = stackLayout }; } private Color GetSuitableBackground(Color color) { double luminance = 0.30 * color.R + 0.59 * color.G + 0.11 * color.B; return luminance > 0.5 ? Color.Black : Color.White; } } }
تأمّل الشيفرة السابقة، وتأكّد من فهمها بشكل جيّد. ثم نفّذ البرنامج باستخدام F5 لتحصل على شكل شبيه بما يلي، علمًا أنّني قد استخدمت ميزة التمرير الجديدة لإظهار بقية العناصر التي لم تكن تظهر معنا من قبل:
ستلاحظ أنّ كلّ لون يظهر في هذه القائمة، له لون خلفيّة مناسب له لإظهاره بالشكل الأمثل.
ملاحظة
يمكنك استخدام الخاصيّة Spacing
لمخطّط المكدّس لزيادة أو إنقاص مقدار التباعد بين اللصائق labels التي تظهر على الشاشة. للخاصيّة Spacing
القيمة الافتراضيّة 6.0
كما أسلفنا، جرّب أن تعيّن القيمة 0 لها مثلًا وانظر على ماذا ستحصل. يمكنك تعيين هذه الخاصيّة بالنسبة للبرنامج السابق بأن تضيف السطر التالي:
stackLayout.Spacing = 0;
بعد السطر التالي مباشرةً:
StackLayout stackLayout = new StackLayout();
الخلاصة
تعرّفنا في هذا الدرس على مبادئ التعامل مع مخطّط المكدّس StackLayout
الذي يُستخدَم في تطبيقات Xamarin على نحو واسع لترتيب العناصر المرئية على الشاشة بشكل متكدّس. تعرّفنا أيضًا على كيفيّة إكساب مخطّط المكدّس ميزة التمرير لكي نستطيع عرض العناصر التي لا تظهر على الشاشة. سنتابع عملنا مع مخطّط المكدّس في الدرس التالي، حيث سنتحدّث عن المزيد من المزايا المهمّة التي يتمتّع بها هذا المخطّط.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.