استخدام مخطّط الشبكة Grid لبناء واجهات متقدّمة


حسام برهان

يُعتبر مخطّط الشبكة Grid Layout من المخطّطات الهامّة والضروريّة في تصميم واجهات المستخدم بالنسبة لتطبيقات الأجهزة المحمولة. فيمكن من خلال هذا المخطّط التحكّم على نحو دقيق نسبيًّا بمواقع جميع العناصر المرئيّة الموجودة في الواجهة، وذلك بخلاف مخطّط المكدّس Stack Layout الذي تناولناه منذ بداية هذه السلسلة حتى الآن. حيث كان من الصعوبة التحكّم بمواقع العناصر المرئيّة بشكل دقيق، وخاصةً فيما يتعلّق بالمحاذاة. في الحقيقة يمكن استخدام كل من هذين المخطّطين معًا في الواجهة الواحدة.

main.png

سنبدأ في هذا الدرس بالتعرّف على مفهوم هذا المخطّط وطريقة استخدامه. ثمّ نُتْبع هذا الدرس بدرسين آخرين يتناولان تطبيقين عمليين لاكتساب الخبرة اللازمة للعمل مع مخطّط الشبكة بسهولة ويسر أكبر.

ما هو مخطّط الشبكة؟

مخطّط الشبكة هو عبارة عن بنية تشبه الجدول من الناحية الشكلية ولكنّها تختلف عنه من الناحية العمليّة. فمخطّط الشبكة قد صُمّم بالأساس ليكون وسيلة لتنظيم العناصر المرئيّة ضمن واجهة المستخدم. أمّا الجدول فهو بنية وظيفتها احتواء بيانات يمكن عرضها للمستخدم.

سيكون أغلب تعاملنا مع مخطّط الشبكة من خلال رُماز XAML. إذ أنّه من الممكن أيضًا استخدام الأسلوب البرمجيّ في التعامل معه. ولكن التعامل معه من خلال الرُماز أفضل من ناحية الاستخدام والتنظيم. يمكن تعريف مخطّط الشبكة من خلال الوسم . حيث من الممكن تعيين الأسطر rows والأعمدة columns التي يتألّف منها هذا المخطّط من خلال الخاصيّتين RowDefinitions التي تحتوي على تعاريف الأسطر وColumnDefinitions التي تحتوي على تعاريف الأعمدة. يُدعى مكان تقاطع السطر والعمود بالخليّة Cell. الخاصيّة RowDefinitions هي عبارة عن مجموعة collection من العناصر التي يكون كلّ منها من النوع RowDefinition وتعني تعريف سطر. يمكن من خلال هذا النوع ضبط العديد من خصائص هذا السطر. سنهتم حاليًّا بالخاصيّة Height التي تُعبّر عن ارتفاع السطر. من الممكن تعيين قيمة هذا الارتفاع بثلاثة أنواع من المقاييس:

  • النوع الأوّل هو القيمة العدديّة المباشرة وهي قيمة لا تتعلّق لا تتعلّق بالشاشة device-independent units (انظر هذا الدرس).
  • النوع الثاني هو الكلمة Auto، والتي تعني أنّه ينبغي أن يكون ارتفاع السطر مساويًا لأعلى ارتفاع عنصر مرئي موجود ضمنه.
  • النوع الثالث هو النوع النسبيّ، ويُعبّر عنه رمز النجمة (*)، حيث يكون ارتفاع السطر في هذه الحالة بحيث يشغل باقي الارتفاع المتاح لمخطّط الشبكة ككل. ومن الممكن أن يتعلّق أيضًا بسطر آخر له نفس هذا النوع من القياس، وسنوضّح ذلك في مثال تطبيقي بعد قليل.

أمّا بالنسبة للخاصيّة ColumnDefinitions هي عبارة عن مجموعة collection من العناصر التي يكون كلّ منها من النوع ColumnDefinition وتعني تعريف عمود. يمكن من خلال هذا النوع ضبط العديد من خصائص هذا العمود. سنهتم بالخاصيّة Width منه التي تُعبّر عن عرض العمود. من الممكن تعيين قيمة هذا العرض كما هو الحال مع تعريف السطر أيضًا بثلاثة أنواع من المقاييس، تماثل من حيث المبدأ الأنواع الثلاثة السابقة من القياس للسطر:

  • النوع الأوّل هنا هو نفسه النوع الأوّل بالنسبة للسطر، وهو قيمة العدديّة المباشرة التي لا تتعلّق لا تتعلّق بالشاشة device-independent units.
  • النوع الثاني هو الكلمة Auto، والتي تعني أنّه ينبغي أن يكون عرض العمود مساويًا لأعرض عنصر مرئي موجود ضمنه.
  • النوع الثالث هو النوع النسبيّ، ويُعبّر عنه رمز النجمة (*) أيضًا، حيث يكون عرض العمود في هذه الحالة بحيث يشغل باقي العرض المتاح لمخطّط الشبكة ككل. ومن الممكن أن يتعلّق أيضًا بعمود آخر له نفس هذا النوع من القياس.

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

تطبيق عملي بسيط باستخدام مخطّط الشبكة

ابدأ بإنشاء مشروع جديد من النوع Blank App (Xamarin.Forms Portable) وسمّه SimpleGridApp، ثم أبق فقط على المشروعين SimpleGridApp (Portable) و SimpleGridApp.Droid كما وسبق أن فعلنا في هذا الدرس. بعد ذلك سنضيف صفحة محتوى تعتمد على رُماز XAML كما وسبق أن فعلنا في هذا الدرس سنسمّها SimpleGridPage. احرص على أن تكون محتويات هذه الصفحة على الشكل التالي:

1	<?xml version="1.0" encoding="utf-8" ?>
2	<ContentPage  xmlns="http://xamarin.com/schemas/2014/forms"
3	              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
4	              x:Class="SimpleGridApp.SimpleGridPage">
5	  <Grid>
6	    <Grid.RowDefinitions>
7	      <RowDefinition Height="Auto" />
8	      <RowDefinition Height="100" />
9	      <RowDefinition Height="2*" />
10	      <RowDefinition Height="1*" />
11	    </Grid.RowDefinitions>
12	    
13	    <Grid.ColumnDefinitions>
14	      <ColumnDefinition Width="*" />
15	      <ColumnDefinition Width="*" />
16	    </Grid.ColumnDefinitions>
17	    
18	    <Label Text="مخطط الشبكة"
19	      Grid.Row="0" Grid.Column="0"
20	      FontSize="Large"
21	      HorizontalOptions="End" />
22	    
23	    <Label Text="تجربة مخطط الشبكة"
24	      Grid.Row="0" Grid.Column="1"
25	      FontSize="Small"
26	      HorizontalOptions="End"
27	      VerticalOptions="End" />
28	    
29	    <Image BackgroundColor="Gray"
30	      Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Source="icon.png" />
31	      
32	    <BoxView Color="Green"
33	      Grid.Row="2" Grid.Column="0" />
34	    
35	    <BoxView Color="Red"
36	      Grid.Row="2" Grid.Column="1" Grid.RowSpan="2" />
37	    
38	    <BoxView Color="Blue"
39	      Opacity="0.5"
40	      Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" />
41	  </Grid>
42	</ContentPage>

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

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

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

fig01.png

لنحلّل الآن هذا التطبيق البسيط. في البداية أنشأنا مخطّط شبكة عن طريق كتابة الوسم اعتبارًا من السطر 5. بعد ذلك وضعنا تعاريف أسطر الشبكة من السطر 6 حتى السطر 10 على الشكل التالي:

<Grid.RowDefinitions>
  <RowDefinition Height="Auto" />
  <RowDefinition Height="100" />
  <RowDefinition Height="2*" />
  <RowDefinition Height="1*" />
</Grid.RowDefinitions>

ويعني ذلك أنّ هذه الشبكة سيكون لها أربعة أسطر (لوجود أربعة وسوم RowDefinition). سيكون ارتفاع السطر الأوّل Auto، ويعني ذلك أنّ هذا السطر سيكون ارتفاعه مساويًا لارتفاع أعلى عنصر موجود ضمنه. أمّا السطر الثاني فارتفاعه 100 وحدة مستقلة عن الجهاز. بالنسبة للسطرين الثالث والرابع فسيكون ارتفاعهما نسبيًّا لوجود رمز النجمة *. لاحظ وجود الرقم 2 بجوار رمز النجمة بالنسبة للسطر الثالث، ووجود الرقم 1 بجوار رمز النجمة بالنسبة للسطر الرابع. الذي سيحدث هنا أنّه وبعد أن يتم تعيين ارتفاعيّ السطرين الأوّل والثاني سيتم اقتسام الارتفاع المتبقي للشبكة بين السطرين الثالث والرابع بحيث تكون حصّة السطر الثالث ضعف (الرقم 2) حصّة السطر الرابع (الرقم 1). بعبارة أخرى ارتفاع السطر الثالث سيكون 2 إلى 1 من ارتفاع السطر الرابع.

وضعنا بعد ذلك تعاريف أعمدة الشبكة من السطر 13 حتى السطر 16 على الشكل التالي:

<Grid.ColumnDefinitions>
  <ColumnDefinition Width="*" />
  <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

من الواضح أنّه سيكون لهذه الشبكة عمودان فقط. كل من هذين العمودين سيكون عرضه نسبيّ (الرمز *). ولكن بسبب عدم وجود أيّ رقم بجوار رمز النجمة في كلّ منهما، سيتمّ اعتبار وجود الرقم 1 بشكل افتراضيّ بجوار كل رمز نجمة (مثل1*). أي بالمحصلة سيكون لكل منهما نفس الرقم، وبالتالي نفس الحصّة النسبيّة لذلك سيكون لهما نفس العرض تمامًا.

تأتي بعد ذلك العناصر المرئيّة التي سنضعها ضمن هذه الشبكة. يبدأ ترقيم كل من الأسطر والأعمدة بالرقم صفر. فالسطر رقم صفر هو السطر الأوّل، وكذلك الأمر بالنسبة للأعمدة. إذا نظرت إلى الأسطر من 18 حتى 21 فستجد أنّنا نضيف لصيقة إلى الخليّة المحدّدة بالسطر الأوّل والعمود الأوّل. ويكمن سبب ذلك في السطر 19 حيث نجد الخاصيّتين Grid.Row="0" للسطر رقم 0، وGrid.Column="0" للعمود رقم 0 أيضًا. أي السطر الأوّل والعمود الأوّل. بنفس الأسلوب تمامًا نضيف لصيقة أخرى إلى الخليّة المحدّدة بالسطر الأوّل والعمود الثاني (الأسطر من 23 حتى 27)، وأيضًا عنصر صورة ضمن الخليّة المحدّدة بالسطر الثاني والعمود الأوّل (السطران 29 و30). نلاحظ أيضًا أنّ عنصر الصورة هذا سيشغل بالإضافة إلى العمود الأوّل العمود الثاني أيضًا، وذلك بسبب وجود الخاصيّة Grid.ColumnSpan="2" والتي تشير إلى أنّ الخليّة التي ستحتوي عنصر الصورة يجب أن تمتد على عمودين متتاليين باتجاه اليمين، وهذا ما يُفسّر سبب ظهورها ممتدّة على كامل عرض الشبكة كما هو واضح في الشكل السابق. بعد إضافة عنصر الصورة السابق، سنضيف ثلاثة عناصر BoxView لأغراض العرض فقط (الأسطر من 32 حتى 40). حيث ستشغل هذه العناصر الثلاثة على الترتيب الخلايا المحدّدة بالسطر الثالث والعمود الأوّل، ثم السطر الثالث والعمود الثاني، ثم السطر الرابع والعمود الأوّل. مع ملاحظة أنّ عنصر BoxView الأوسط يحوي الخاصيّة Grid.RowSpan="2" التي تسمح للخلية التي تحتويه بالامتداد إلى سطرين متتاليين. أمّا عنصر BoxView الأخير فيحوي على الخاصية Grid.ColumnSpan="2" لتسمح له بالامتداد على عمودين متتاليين. أي أنّ عنصريّ BoxView الثالث والرابع سيتداخلان في الخليّة المحدّدة بالسطر الرابع والعمود الثاني كما هو واضح من الشكل السابق.

الخلاصة

تعلّمنا في هذا الدرس كيفيّة التعامل الأساسي مع مخطّط الشبكة Grid Layout. ولعلّ الفهم الأفضل لمثل هذه الأمور تنبع من الممارسّة العمليّة ببناء تطبيقات عمليّة صغيرة ولكنّها مفيدة. سنعمل في الدرسين القادمين على بناء تطبيقين بسيطين يحتويان على العديد من التقنيّات البرمجيّة المفيدة والتي من الممكن استخدامها في التطبيقات الواقعيّة.





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


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



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

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

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


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

تسجيل الدخول

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


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