العناصر المرئيّة الشائعة في Xamarin – الجزء الثاني


حسام برهان

سنتابع عملنا في سلسلة تعلّم تطوير تطبيقات أندرويد باستخدام Xamarin.Forms مع الجزء الثاني للعناصر المرئيّة الشائعة في Xamarin.Forms. تناولنا في الجزء الأوّل بعضًا من هذه العناصر حيث تحدثنا عن عناصر القائمة ListView وحقل الإدخال Entry وعنصر تحويل الحالة المنطقيّة Switch كما تحدثنا أيضًا عن عنصر المنزلق Slider.

main.png

سنتحدّث في هذا الدرس عن عنصر DatePicker الذي يسمح باختيار تاريخ محدّد بطريقة جميلة، كما سنتحدّث عن عنصر الاختيار الخطوي Stepper الذي يشبه عنصر المنزلق Slider، وأيضًا عنصر الإطار Frame الذي يُستَخدم لتعزيز الناحية الجمالية لواجهة المستخدم. سنتناول تطبيقين عمليّين لتوضيح عمل هذه العناصر.

تطبيق التحكّم بعرض الحدود

وهو تطبيق بسيط للغاية، الغرض منه توضيح كيفيّة استخدام العنصر Stepper. يمتلك هذا العنصر بنية برمجيّة شبيهة بعنصر المنزلق Slider الذي تحدثنا عنه في الدرس السابق، رغم أنّه يختلف عنه من الناحية الشكليّة، فهذا العنصر يتكوّن من زرّين متجاورين يظهر عليهما النصّان "+" و "-". توجد ميزة إضافية في هذا العنصر تتمثّل في وجود خاصيّة اسمها Increment قيمتها الافتراضيّة 1. وتُستخدم لتحديد مقدار الزيادة أو النقصان عند كل نقرة على الزرّين السابقين كما سنرى بعد قليل. يُستخدم عنصر Stepper غالبًا لاختيار قيم عدديّة صحيحة (بدون فاصلة عشريّة) مع أنّه من الممكن استخدام القيم العشرية معه.

أنشئ مشروعًا من النوع Blank App (Xamarin.Forms Portable) وسمّه StepperDemoApp، ثم أبق فقط على المشروعين StepperDemoApp (Portable) و StepperDemoApp.Droid كما وسبق أن فعلنا في هذا الدرس. بعد ذلك أضف صفحة محتوى جديدة كما فعلنا في هذا الدرس وسمّها StepperDemoPage. احرص على أن تكون محتويات الملف StepperDemoPage.cs على الشكل التالي:

1	using Xamarin.Forms;
2	
3	namespace StepperDemoApp
4	{
5	    public class StepperDemoPage : ContentPage
6	    {
7	        public StepperDemoPage()
8	        {
9	            Button btnDemo = new Button
10	            {
11	                Text = "اختبار سماكة حدود الزر",
12	                FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Button)),
13	                BorderColor = Color.FromHex("C0C0C0"),
14	                BackgroundColor = Color.FromHex("404040"),
15	                HorizontalOptions = LayoutOptions.Center,
16	                VerticalOptions = LayoutOptions.CenterAndExpand
17	            };
18	
19	            Label lblCurrentBorderWidth = new Label
20	            {
21	                Text = "السماكة الحالية: 0",
22	                HorizontalOptions = LayoutOptions.FillAndExpand,
23	                HorizontalTextAlignment = TextAlignment.Center
24	            };
25	
26	            Stepper stepper = new Stepper
27	            {
28	                HorizontalOptions = LayoutOptions.Center,
29	                Maximum = 10,
30	                Minimum = 0
31	            };
32	            stepper.ValueChanged += (s, e) =>
33	            {
34	                btnDemo.BorderWidth = stepper.Value;
35	
36	                lblCurrentBorderWidth.Text = "السماكة الحالية: " + stepper.Value.ToString();
37	            };
38	            
39	            StackLayout changeBorderWidthSLayout = new StackLayout
40	            {
41	                VerticalOptions = LayoutOptions.CenterAndExpand,
42	                Children =
43	                {
44	                    lblCurrentBorderWidth,
45	                    stepper
46	                }
47	            };
48	
49	            Content = new StackLayout
50	            {
51	                Children =
52	                {
53	                    btnDemo,
54	                    changeBorderWidthSLayout
55	                }
56	            };
57	        }
58	    }
59	}

انتقل إلى الملف App.cs واحرص على أن تكون بانية الصنف App على الشكل التالي:

public App()
{
    // The root page of your application
    MainPage = new StepperDemoPage();
}

نفّذ البرنامج باستخدام F5، ثم تفاعل مع التطبيق بنقر الزرّين "+" و "-" لتحصل على شكل شبيه بما يلي:

fig01.png

يتكوّن التطبيق من زر في الأعلى يحوي النص "اختبار سماكة الحدود" بالإضافة إلى عنصر Stepper يسمح لك بضبط قيمة الحدود لهذا الزر، وأيضًا توجد لصيقة صغيرة تعلو العنصر Stepper وظيفتها عرض القيمة الحالية المختارة لسماكة حد الزر. صرّحنا في الأسطر من 9 حتى 17 عن عنصر زر جديد وأسندناه إلى المتغيّر btnDemo. لقد جعلنا الخط المُستخدَم في هذا الزر كبيرًا، وأيضًا ضبطنا لون الحد عن طريق الخاصيّة BorderColor (السطر 13) ليكون هذا اللون "C0C0C0" وهي قيمة ست عشرية تتكوّن من 3 مكوّنات لونية هي من اليسار إلى اليمين: الأحمر والأخضر والأزرق بحيث يأخذ كل مكوّن لوني محرفين. فمن خلال القيمة "C0C0C0" سيأخذ كل من الأحمر والأخضر والأزرق القيمة C0 وهي حالة خاصّة بالطبع وسنحصل من خلالها على أحد تدرّجات اللون الرمادي. بنفس الأسلوب قمنا بضبط لون الخلفيّة لهذا الزر من خلال الخاصيّة BackgroundColor (السطر 14) ليكون "404040" وهو أيضًا أحد تدرّجات الرمادي. يمكنك اختيار أيّ لون ترغبه.

سنضع كلًّا من اللصيقة المسؤولة عن عرض قيمة الحد الحالي lblCurrentBorderWidth (الأسطر من 19 حتى 24) وأيضًا عنصر الاختيار الخطوي stepper (الأسطر من 26 حتى 31) ضمن مخطّط مكدّس ليظهرا متجاورين رأسيًّا. مخطّط المكدّس هذا مصرّح عنه في الأسطر من 39 حتى 47 عن طريق المتغيّر changeBorderWidthSLayout. لاحظ أخيرًا أنّنا قد صرّحنا عن معالج الحدث ValueChanged للعنصر stepper بصورة مماثلة تمامًا لما فعلناه مع عنصر المنزلق Slider في الدرس السابق، وذلك في الأسطر من 32 حتى 37 لكي نعالج نقرات المستخدم على هذا العنصر، وبنفس الوقت نحدّث قيمة اللصيقة لتعرض السماكة الحاليّة لحدود الزر (السطر 36).

تطبيق حساب العمر بالأيّام

نحتاج لإنجاز هذا التطبيق إلى عنصر DatePicker لاختيار تاريخ الولادة، وعنصر Frame لإكساب صفة جمالية على التطبيق كما سنرى، كما سنحتاج إلى زر لإجراء عمليّة الحساب ولصيقة لعرض النتيجة. سيتم حساب العمر الحالي بالأيّام من تاريخ الولادة حتى تاريخ اليوم. أنشئ مشروعًا من النوع Blank App (Xamarin.Forms Portable) وسمّه AgeCalculatorApp، ثم أبق فقط على المشروعين AgeCalculatorApp (Portable) وAgeCalculatorApp.Droid. بعد ذلك أضف صفحة محتوى جديدة وسمّها AgeCalculatorPage. احرص على أن تكون محتويات الملف AgeCalculatorPage.cs على الشكل التالي:

1	using System;
2	using Xamarin.Forms;
3	
4	namespace AgeCalculatorApp
5	{
6	    public class AgeCalculatorPage : ContentPage
7	    {
8	        public AgeCalculatorPage()
9	        {
10	            Frame frmWelcome = new Frame
11	            {
12	                VerticalOptions = LayoutOptions.Start,
13	                Padding = new Thickness(15),
14	                BackgroundColor = Color.FromRgba(Color.Accent.R, 
15	                                                Color.Accent.G, 
16	                                                Color.Accent.B,
17	                                                0.2),
18	                OutlineColor = Color.Accent,
19	                Content = new Label
20	                {
21	                    Text = "تطبيق حساب العمر بالأيّام",
22	                    FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
23	                    TextColor = Color.Aqua,
24	                    HorizontalTextAlignment = TextAlignment.Center
25	                }
26	            };
27	             
28	
29	            DatePicker birthDate = new DatePicker
30	            {
31	                VerticalOptions = LayoutOptions.Start,
32	                HorizontalOptions = LayoutOptions.FillAndExpand,
33	                
34	            };
35	
36	            Label lblCurrentDate = new Label
37	            {
38	                Text = DateTime.Now.ToString("dd/MM/yyyy"),
39	                VerticalOptions = LayoutOptions.Start,
40	                HorizontalOptions = LayoutOptions.FillAndExpand,
41	                FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label))
42	            };
43	
44	            Label lblResult = new Label
45	            {
46	                VerticalOptions = LayoutOptions.FillAndExpand,
47	                FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
48	                VerticalTextAlignment = TextAlignment.Start,
49	                HorizontalTextAlignment = TextAlignment.Center,
50	                TextColor = Color.Accent
51	            };
52	
53	            Button btnCalculate = new Button
54	            {
55	                Text = "احسب",
56	                VerticalOptions = LayoutOptions.Start
57	            };
58	            btnCalculate.Clicked += (s, e) =>
59	            {
60	                TimeSpan diff = DateTime.Now - birthDate.Date;
61	
62	                lblResult.Text = string.Format("عمرك {0} يومًا", diff.Days);
63	            };
64	
65	            Content = new StackLayout
66	            {
67	                Children =
68	                {
69	                    frmWelcome,
70	                    birthDate,
71	                    lblCurrentDate,
72	                    btnCalculate,
73	                    lblResult
74	                }
75	            };
76	
77	            Padding = new Thickness(5);
78	        }
79	    }
80	}

انتقل بعد ذلك إلى الملف App.cs وتأكّد أنّ بانية الصنف App على الشكل التالي:

public App()
{
    // The root page of your application
    MainPage = new AgeCalculatorPage();
}

نفّذ البرنامج باستخدام F5 لتحصل على شكل شبيه بما يلي:

fig02.png

اختر تاريخ مولدك (الميلادي) ولاحظ الصندوق الذي يملأ حيزًا لا بأس به من الشاشة، وكف يسمح لك باختيار التاريخ بصورة جميلة. بعد أن تختار التاريخ المناسب لك، انقر زر "احسب" لتحصل على عمرك بالأيّام من الأسفل. أنشأنا في الأسطر من 10 حتى 26 كائن جديد من الصنف Frame وأسندناه إلى المتغيّر frmWelcome. تُعتبر عناصر Frame ذات بنية مستطيلة تُستخدم لأغراض تحسين واجهة المستخدم. يعرض عنصر Frame حدًّا مستطيلًا يحيط بمحتوى معيّن. وإليك الآن بعض الملاحظات البسيطة حوله:

  • يحتوي عنصر الإطار Frame على الخاصيّة Content التي يمكن أن نُسند إليها أي عنصر آخر، أو من الممكن أن نسند إليها مخطّط مكدّس يحتوي بدوره على العديد من العناصر الأخرى. في مثالنا هذا أسندنا إلى هذه الخاصيّة كائن لصيقة Label (السطر 19) يحتوي على عنوان التطبيق.
  • يضم عنصر الإطار أيضًا الخاصيّة Padding لإضافة حشوة داخليّة بين حدود الإطار والمحتوى الذي يقع ضمنه (السطر 13).
  • يمكن التحكّم بلون حد الإطار من خلال الخاصيّة OutlineColor (السطر 18) حيث عملنا في هذا التطبيق على إسناد اللون Color.Accent إليه.
  • الخاصيّة BackgroundColor للإطار تتحكّم بلون الخلفيّة كما نعلم، ولكن لاحظ الشكل الجديد الذي استخدمناه في إسناد اللون لها هذه المرّة (الأسطر من 14 حتى 17). استخدمنا هذه المرّة التابع Color.FromRgba الذي يُرجع كائن من النوع Color اعتبارًا من القيم اللونية RGB ومقدار الشفافيّة A الممرّرة إليه. ونستفيد من هذا الشكل في الحصول على ألوان مخصّصة أكثر. أحببت أن أستخدم اللون Accent ولكن بشكل شفّاف لذلك حصلت على المركّبات اللونية له باستخدام Color.Accent.R للأحمر وColor.Accent.G للأخضر وColor.Accent.B للأزرق، ومرّرتها إلى التابع Color.FromRgba بنفس الترتيب السابق. أمّا الوسيط الأخير فقد مرّرت إليه القيمة 0.2 ليظهر اللون شفَّافًا. قيمة الوسيط الأخير (قيمة A) تتراوح بين 0 (شفّاف تمامًا) و1 (معتم تمامًا).

بالنسبة للعنصر DatePicker فيُستخدم كما أشرنا لاختيار تاريخ محدّد بصورة جميلة. صرّحنا عنه في الأسطر من 29 حتى 34 وأسندنا الكائن الناتج إلى المتغيّر birthDate ويُعبّر عن تاريخ الولادة. إليك بعض الملاحظات المتعلّقة بهذا العنصر:

  • يمكن الوصول إلى قيمة التاريخ الموجودة حاليًا ضمن هذا العنصر عن طريق الخاصيّة Date له كما سنرى بعد قليل. نوع هذه الخاصيّة مألوف وهو DateTime.
  • توجد خاصيّتان مفيدتان في بعض الأحيان ولكن لم نستخدمهما في هذا التطبيق، وهما MinimumDate لتحديد التاريخ الأدنى الذي لا يمكن الاختيار قبله، و MaximumDate لتحديد التاريخ الأعلى الذي لا يمكن الاختيار بعده.

خصّصنا لصيقة بسيطة لعرض النتائج (الأسطر من 44 حتى 51) وصرّحنا أيضًا عن الزر الخاص بإجراء عمليّة الحساب (الأسطر من 53 حتى 57) وأسندناه إلى المتغيّر btnCalculate. أسندنا معالج حدث النقر لهذا الزر في الأسطر من 58 حتى 63 على شكل تعبير Lambda. يحتوي هذا المعالج على شيفرة برمجيّة بسيطة للغاية، فهو يقرأ قيمة الخاصيّة Date من المتغيّر birthDate ويطرحها من التاريخ الحالي ويُسند النتيجة إلى المتغيّر diff الذي سيكون في هذه الحالة من النوع TimeSpan وهي بنية يمكن استخدامها لقياس فترات زمنيّة مُحدّدة (السطر 60) في نهاية الأمر نستخدم الخاصيّة Days من المتغيّر diff للحصول على الفترة الزمنية المطلوبة والتي تمثّل عمر الشخص بالأيّام.

قد لا يبدو مظهر هذا التطبيق احترافيًّا كفاية. ولكنّنا سنتعلّم من خلال الدروس القادمة كيفيّة تحسين واجهة المستخدم وجعلها جذّابة من خلال تقنيّات بسيطة نسبيًّا.

الخلاصة

تعاملنا في هذا الدرس مع بعض العناصر المرئيّة المستخدمة في Xamarin.Forms. توجد بعض العناصر الأخرى التي لم نتحدّث عنها، أو التي لم نعطها حقّها في الحديث عنها. في الواقع أفضّل تأجيل ذلك إلى دروس قادمة لأنّ استخدام بعض هذه العناصر يتطلّب مفاهيم متقدّمة نسبيًّا في Xamarin.Forms. سنبدأ في الدرس التالي تعلّم كيفيّة بناء الواجهات باستخدام رُماز XAML. حيث سنتمكّن من فصل واجهة المستخدم عن الشيفرة البرمجيّة التي تتفاعل معها.





تفاعل الأعضاء


لا توجد أيّة تعليقات بعد



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن