تحسين تجربة المستخدم في التعامل مع الـ TableView
أهلاً ومرحباً بكم في مدونتي الجديدة =)
مدونتي السابقة كانت g-kn.com تم إغلاقها للانتقال لهذه المنصة الجميلة ،مقالاتي السابقة تجدونها في موقع عالم البرمجة على هذا الرابط
كمطور تطبيقات جوال فإنك سوف تعتمد اعتماد كبير على TableView
تقريبا لا يخلوا تطبيق جوال من الـ TableView
أيضا جميع المستخدمين النظام معتادين على التعامل مع الـ TableView
فكيف يمكنك تحسينه وإضافة قيمة مضافة تسهل حياة المستخدم وتحببه لتطبيقك ؟
في حال كنت تعرض محتوى كبير في الـ TableView
كمثال تطبيقك عباره عن شبكة اجتماعية ، قارئ RSS ، تطبيق ايميل
او أي تطبيق مشابه بحيث تعرض محتوى كبير
فهذا الموضوع سوف يفيدك =)
بداية دعني أوضح الفكرة
الفكرة الذي نريد عملها عبارة عن خطوتين
الخطوة الأول : حفظ اخر Cell وصل له المستخدم وبالتالي عند اغلاق التطبيق وفتحه مره أخرى سوف نعيد المستخدم الى اخر Cell كان واقف عليه ، اذا لاحظت فإن الفكرة هذه مطبقة في الشبكات الاجتماعية عند اغلاقك التطبيق وفتحه مره أخرى فإنه يظهر لك اخر Cell كنت متوقف عنده !
الخطوة الثانية : تجنب نسبة الخطأ الذي قد يرتكبها المستخدم عند استخدام تطبيقك ماذا اقصد ؟
من الأمور المعروفة لذا مستخدمين الـ iOS ، هي يمكنهم الضغط على شريط الساعة للوصول لأول Cell في الـ TableView ، وبالتالي الامر سوف يكون مزعجاً عند حدوث هذا الامر عن طريق الخطأ !
لذا سوف نقوم بحل هذه المشكلة ! ، كيف ؟ سوف نجعل المستخدم يعد الى نفس الـ Cell عند الضغط على شريط الساعة مره أخرى ! ، بما يعني اول مره سوف ينتقل الى أول Cell لكن الضغطة الثانية سوف تعيده الى نفس الـ Cell التي كان متوقف عندها ! بالضبط كما يفعل تطبيق TweetBot
الشرح :
في البداية قم بعمل مشروع جديد واضيف الـ TableView وقم بعمل اللازم من توصيله بالـ delegate والـ dataSource وأيضا لا تنسى تعطي للـ Cell معرف (identity) في مثالي اعطيته معرف dataCell
الكود سوف يكون بالشكل الحالي :
شرح الخطوة الأول :
في هذه الخطوة كما ذكرنا سابقاً نحتاج الى حفظ اخر Cell وصل اليه المستخدم
ومن ثم عند فتح التطبيق مره اخرى سوف نقوم بعرض الجدول على نفس الـCell
اسهل طريقة لحفظ بيانات بسيطه هو استخدام UserDefaults
لكن لحظة الـ UserDefaults لا يسمح بالحفظ الا بيانات معينه فقط وهذه انواعها
integer, bool, float, double ،فكيف سوف نحفظ الـ indexPath ؟
الإجابة هي لا نحتاج الى حفظ الـ indexPath كما هو ولكن فقط نحتاج نحفظ رقم الـ Row لماذا ؟ في مثالنا السابق لا يوجد غير section واحد فقط بما يعني أنه لن يتغير وفقط قيمة الـ Row سوف تتغير لذا اسهل طريقة سوف تكون حفظ قيمة الـ Row ومن ثم إعادة إنشاء الـ indexPath عندما نحتاجه.
تستنتج بما سبق بأنك سوف تحتاج الى حفظ رقم الـ section ايضا في حال كان الـ Tableview الذي تستخدمه يحتوي على عدة sections
على أي حال عند استخدامي للـ UserDefaults فإني افضل عمل struct له ليسهل الوصول له في اي مكان من التطبيق وبدون الحاجة لإعادة كتابة نفس الأكواد عدة مرات، لذا تستطيع كتابة الكود التالي اما في ملف swift جديد أو خارج class ViewContorller
الان سوف نحتاج الي كتابة كود معين يقول بحفظ اول Cell ظاهر في الـ TableView
اين سوف نستخدم هذا الـ Function ؟ ، سوف نسخدمه ضمن ميتودين من ميتودات الـ Tableview delegate
الميتودين هيا scrollViewDidEndDecelerating
و scrollViewDidEndDragging
scrollViewDidEndDecelerating : يعمل عندما ينتقل المستخدم بشكل سريع ومن ثم يتوقف
scrollViewDidEndDragging : يعمل عندما ينتقل المستخدم بين الـ Cells بشكل طبيعي
وبما إننا لا نستطيع توقع المستخدم وطريقة استخدامه وتصفحه للـCells فالافضل استدعاء الـ helperScrollEnd في الميتودين
وعموما دائما افضل فصل الـ delegate والـ dataSource في extension
منفصله عن بعض بالطريقة دي الكود يكون ارتب واسهل في الوصول للكود المطلوب من اني أدمجهم مع بعض.
اضيف الكود التالي خارج الكلاس
باقي جزيئة واحده فقط ، الان حفظنا موقع اخر Cell ، نحتاج عند فتح التطبيق بأن نظهر الجدول على الـ Cell المحفوظ بدل من ظهور الجدول على اول Cell
فنحتاج نضيف Function جديد وهذه المره سوف نضيفه في نفس الـ class
اذا لاحظت الـ function السابق اضفنا له parameter بإسم animated الغرض منه لكي نستيطع التحكم في اضافة aniamtion من عدمه ، عند فتح التطبيق نريد أن نظهر الجدول على اخر Cell ولكن بدون animation لكن في الخطوة الثانية عند الضغط على شريط الساعة نريد أن ننتقل الى الـ Cell ولكن مع animation لهذا السبب اضفنا هذا الـ parameter
سوف نستدعي هذا الـ function في viewDidApper وليس في viewDidLoad
الان عند تشغيل التطبيق والسحب للاسفل ومن ثم إغلاق التطبيق او إيقاف المشروع وإعادة تشغيله سوف تلاحظ عند تشغيل التطبيق مره اخرى بأنه يظهر اخر Cell كنت متوقف عندها بكذا نكون انتهينا من الخطوة الاولى
شرح الخطوة الثانية :
في الخطوة الثانية نحتاج نضيف متغير جديد من نوع Bool
المتغير السابق سوف نستفيد منه في معرفة هل تم الانتقال للأعلى ام لا
وأيضا سوف نعود
الى الـ extension ViewController:UITableViewDelegate
ونضيف function جديدة من ضمن الـ Functions المتوفره ضمن الـ delegate
اسمها scrollViewShouldScrollToTop وكما هو واضح من الاسم فإنها مسؤوله عن تفعيل او إغلاق ميزة الانتقال الى بداية الـ TableView
بشكل إفتراضي ترجع قيمة true اذا جعلتها false فإنك سوف تعطل ميزة الانتقال الى بداية الـ TableView عند الضغط على شريط الساعة او كما يسمى Status Bar ونحن سوف نستفيد من الـ function هذه لصالحنا =)
الكود السابق بداية سوف نتأكد من قيمة المتغير الذي اضفناه سابقا didScrollingToTop اذا كان قيمة false فإننا سوف نسمح بالانتقال الى بداية الـ TableView زمن ثم سوف نغير قيمة الـ didScrollingToTop الى true لأننا سوف نصبح في بداية الـ Tableview.
لكن في حالة كان الـ didScrollingToTop بقيمة true فمعناه اننا نريد العودة الى الـ Cell الذي كنا متوقفين عنده عند الضغط على شريط الساعة مره اخرى
لذلك هذه المره سوف نرجع قيمة false لكي نتمكن من استدعاء
returnBackToLastPosition(true) وايضا سوف نعيد قيمة الـ didScrollingToTop الى false
بكذا نكون انتيهنا قم بتشغيل التطبيق ومن ثم اسحب للاسفل ومن ثم اضغط على شريط الساعه سوف ينتقل مباشرة الى بداية الـ TableView الان قم بالضغط على شريط الساعه مره اخرى وسوف يعود تلقائيا الى الـ Cell الذي كنت متوقف عندها سابقا ! كما في الصورة التالية :