التنقّل بين الصفحات في Xamarin


حسام برهان

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

مفهوم التنقّل بين صفحات التطبيق

يشبه التنقّل بين صفحات التطبيق مبدأ عمل المكدّس Stack إلى حدّ كبير. والمكدّس كما هو معلوم هو بنية معطيات تدعم مفهوم LIFO (الذي يدخل أخيرًا يخرج أولًا). فعند الانتقال من الصفحة A إلى الصفحة B، تُدفع pushed الصفحة B إلى أعلى المكدّس مما يؤدّي إلى ظهورها أمام المستخدم. وكذلك الأمر عند الانتقال من الصفحة B إلى الصفحة C يتم دفع الصفحة C إلى المكدّس ليتم إظهارها إلى المستخدم. أمّا عندما نريد العودة إلى الصفحة A الأصلية فيجب عندها أن تُخرج popped الصفحة C من المكدّس فتصبح الصفحة B أعلى المكدّس (أي تظهر للمستخدم) ثم تُخرج الصفحة B من المكدّس فتصبح الصفحة A أعلى المكدّس (أي تظهر للمستخدم). انظر الشكل التالي لتوضيح هذه الفكرة:

fig01.png

صفحات Modal و Modeless

يحتوي على كل تطبيق على صفحة رئيسيّة main page (ستكون من الصنف NavigationPage) تُعتبر العقدة الرئيسيّة التي يمكن الوصول من خلالها إلى جميع الصفحات الأخرى مهما كان عددها ومستواها. كما تميّز Xamarin بين نوعين من صفحات المحتوى التي تُستَخدم ضمن بنية التنقّل هذه وهي: الصفحات الجامدة Modal Pages والصفحات غير الجامدة Modeless Pages. الفرق بين هذين النوعين بالنسبة لتطبيقات أندرويد بسيط. وهو أنّه في الصفحات من النوع Modal لن يتم عرض عنوان الصفحة في الأعلى كما سنرى في المثال بعد قليل. أمّا في الصفحة من النوع Modeless فسيتم عنوان الصفحة في الأعلى في حال تمّ تحديده باستخدام الخاصيّة Title لصفحة المحتوى. لمعاينة الفرق بين هذه الأنواع لننشئ تطبيق عملي بسيط يوضّح هذا الأمر. ابدأ بإنشاء مشروع جديد من النوع Blank App (Xamarin.Forms Portable) وسمّه ModelessAndModal، ثم أبق فقط على المشروعين ModelessAndModal (Portable) و ModelessAndModal.Droid كما وسبق أن فعلنا في هذا الدرس. بعد ذلك سنضيف ثلاث صفحات محتوى عادية (Forms ContentPage) وهي: MainPage و ModalPage و ModelessPage. عدّل محتويات الملف MainPage ليكون مماثلًا لما يلي:

1   using Xamarin.Forms;
2   
3   namespace ModelessAndModal
4   {
5       public class MainPage : ContentPage
6       {
7           public MainPage()
8           {
9               Title = "Main Page";
10  
11              Button gotoModelessButton = new Button
12              {
13                  Text = "Go to Modeless Page",
14                  HorizontalOptions = LayoutOptions.Center,
15                  VerticalOptions = LayoutOptions.CenterAndExpand
16              };
17  
18              gotoModelessButton.Clicked += async (sender, args) =>
19              {
20                  await Navigation.PushAsync(new ModelessPage());
21              };
22  
23              Button gotoModalButton = new Button
24              {
25                  Text = "Go to Modal Page",
26                  HorizontalOptions = LayoutOptions.Center,
27                  VerticalOptions = LayoutOptions.CenterAndExpand
28              };
29  
30              gotoModalButton.Clicked += async (sender, args) =>
31              {
32                  await Navigation.PushModalAsync(new ModalPage());
33              };
34  
35              Content = new StackLayout
36              {
37                  Children = { gotoModelessButton, gotoModalButton }
38              };
39          }
40      }
41  }

ستعرض الصفحة الرئيسية MainPage زرّين فقط. الزر الأوًل هو gotoModelessButton ووظيفته إنشاء صفحة غير جامدة modeless والانتقال اليها. أمّا الزر الثاني فهو gotoModalButton ووظيفته إنشاء صفحة جامدة modal والانتقال إليها. بالنسبة للزر الأوّل gotoModelessButton انظر إلى الأسطر من 11 حتى 21:


Button gotoModelessButton = new Button
{
    Text = "Go to Modeless Page",
    HorizontalOptions = LayoutOptions.Center,
    VerticalOptions = LayoutOptions.CenterAndExpand
};

gotoModelessButton.Clicked += async (sender, args) =>
{
    await Navigation.PushAsync(new ModelessPage());
};

ننشئ في البداية كائنًا من النوع Button ونسنده إلى المتغيّر gotoModelessButton ثمّ نعيّن معالج لحدث النقر Clicked وهو عبارة عن تعبير lambda بسيط يمثّل تابع يحتاج إلى وسيطين sender و e وهو مسبوق بالكلمة المحجوزة async كما هو واضح من الشيفرة السابقة. سبب وجود الكلمة async هو أنّنا سنستخدم استدعاءً غير متزامنًا ضمن معالج الحدث هذا وهو:

await Navigation.PushAsync(new ModelessPage());

يعمل التابع PushAsync المُستدعى من الخاصيّة Navigation للصفحة الحالية على دفع صفحة جديدة ضمن المكدّس الخاص بالتنقّل بين الصفحات، بمعنى آخر، سيعمل هذا التابع على إظهار صفحة جديدة من النمط modeless. في السطر السابق سيتم إنشاء صفحة جديدة من النوع ModelessPage ومن ثمّ تمريرها إلى التابع PushAsync. أنصحك بمراجعة هذا الدرس لكي تنعش ذاكرتك حول موضوع الاستدعاءات غير المتزامنة. نفس الأمر سيجري تمامًا بالنسبة للزر الخاص بالانتقال إلى الصفحة الجامدة مع فارق بسيط. وهو أنّ الاستدعاء هذه المرة سيكون من خلال التابع PushModalAsync (السطر 32) وذلك للانتقال إلى صفحة جامدة (ستكون من الصنف ModalPage). في كلّ من الحالتين السابقتين كان من الممكن أن نجعل معالجي حدثي النقر ضمن تابعين مستقلين وليس كما هو الحال من خلال تعبيري Lambda. الأمر الجدير بالملاحظة بالنسبة للصنف MainPage أيضًا هو تعيين الخاصيّة Title (السطر 9). في الحقيقة لم يكن لهذه الخاصيّة أي معنى في جميع البرامج التي أنشأناها في هذه السلسلة حتى الآن. إذ تعيين هذه الخاصيّة من عدمه لن يُحدث أيّ فرق! الجديد هنا هو في كيفيّة إنشاء الصفحة MainPage بحد ذاتها، والتي سننشئها كم جرت العادة ضمن الصنف App. انتقل إلى الملف App.cs واحرص على أن تكون بانيته مطابقة لما يلي:

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

لاحظ معي الأمر الجديد هنا. نحن لا ننشئ صفحة محتوى ونسندها للخاصيّة MainPage مباشرةً كما كنّا نفعل من قبل. إنّما ننشئ صفحة محتوى (في مثالنا هي من الصنف MainPage) ثم نمرّر هذه الصفحة كوسيط إلى بانية الصنف NavigationPage. أي أنّنا في الواقع ننشئ صفحة محتوى تدعم التنقّل navigation. وهذا ما سيجعل عنوان الصفحة الرئيسيّة المُعيّن باستخدام الخاصيّة Title يظهر أعلى الصفحة كما سنرى بعد قليل. يمكننا الآن أن نجرّب هذا التطبيق. نفّذ التطبيق لتحصل على شكل شبيه بما يلي:

fig02.png

أوقف تنفيذ البرنامج لنبدأ بالمرحلة الأخيرة وهي تجهيز صفحتي المحتوى ModalPage و ModelessPage. انتقل إلى الملف ModalPage.cs واحرص على أن تكون محتوياته مطابقة لما يلي:

using Xamarin.Forms;

namespace ModelessAndModal
{
    public class ModalPage : ContentPage
    {
        public ModalPage()
        {
            Title = "Modal Page";
            Button goBackButton = new Button
            {
                Text = "Back to Main",
                HorizontalOptions = LayoutOptions.Center,
                VerticalOptions = LayoutOptions.Center
            };

            goBackButton.Clicked += async (sender, args) =>
            {
                await Navigation.PopModalAsync();
            };

            Content = goBackButton;
        }
    }
}

ثمّ انتقل إلى الملف ModelessPage.cs واحرص على أن تكون محتوياته كما يلي:

using Xamarin.Forms;

namespace ModelessAndModal
{
    public class ModelessPage : ContentPage
    {
        public ModelessPage()
        {
            Title = "Modeless Page";
            Button goBackButton = new Button
            {
                Text = "Back to Main",
                HorizontalOptions = LayoutOptions.Center,
                VerticalOptions = LayoutOptions.Center
            };

            goBackButton.Clicked += async (sender, args) =>
            {
                await Navigation.PopAsync();
            };

            Content = goBackButton;
        }
    }
}

محتويات كلّ من الصفحتين السابقتين متطابقة. فكل منهما يحتوي على زر اسمه goBackButton هدفه العودة إلى الصفحة السابقة (التي سببت ظهور الصفحة الحالية). هناك فرق بسيط وحيد بين معالجي حدثي النقر للزرين في الصفحتين السابقتين. بالنسبة للصفحة من النمط الجامد modal تم استخدام الاستدعاء غير المتزامن Navigation.PopModalAsync للعودة إلى الصفحة السابقة. أمّا في حالة الصفحة ذات النمط غير الجامد modeless فقد تمّ استخدام الاستدعاء غير المتزامن Navigation.PopAsync للعودة إلى الصفحة السابقة. ثمة فرق آخر عند تنفيذ البرنامج، وهو أنّه في حالة الانتقال من الصفحة الرئيسية إلى الصفحة ModelessPage (الصفحة غير الجامدة) سيظهر عنوان الصفحة في الأعلى مع سهم صغير يسمح لنا بالعودة إلى الصفحة السابقة. أمّا عند الانتقال من الصفحة الرئيسية إلى الصفحة ModePage (الصفحة الجامدة) فلن يظهر عنوان الصفحة أبدًا (رغم تعيين الخاصيّة Title لها)، والوسيلة الوحيدة للرجوع إلى الصفحة السابقة هي بنقر زر الرجوع الموجود ضمن الصفحة أو بنقر زر العودة إلى الوراء الذي يزوّدنا به نظام التشغيل. أجرِ بعض التجارب على التطبيق ولاحظ الفرق بين الصفحتين.

Quote

تُستَخدم الصفحات الجامدة عادةً عندما نريد من المستخدم أن يزوّد التطبيق بمعلومات أساسيّة قبل أن ينتقل إلى صفحة أخرى. في الحقيقة تستخدم أغلب تطبيقات أندرويد النمط غير الجامد modeless في عملها.

 

الخلاصة

تناولنا في هذا الدرس آلية التنقّل بين الصفحات في تطبيقات أندرويد، وهو موضوع مهمّ بالطبع. حيث تعرّفنا إلى الفرق بين الصفحات من النمط modal والنمط modeless. كما تعلّمنا كيفية إنشاء الصفحة الرئيسيّة التي تُعتبر حجر البناء الأساسي في عمليّة الانتقال بين الصفحات، وذلك من خلال إنشاء الصفحة الرئيسيّة لتكون من النوع NavigationPage.





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


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



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

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

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


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

تسجيل الدخول

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


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