العنوان سيكون مختلفا

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



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



2 من 24 . ويبدو أن أحدهما قد فعل ذلك عن طريق الصدفة: فكلما زاد حجم الخط ، "تعوم" الواجهة بأكملها ويصبح من الصعب استخدامها فقط. إنه لأمر محزن.

يستخدم 550،000 شخص تطبيق Dodo Pizza iOS كل شهر. حتى لو كان 1٪ من مستخدمينا قاموا بتوسيع الخط ، فإن 5500 شخصًا غير مرتاحين لاستخدام تطبيقنا. سنقوم بتصحيحه.

إضافة دعم نوع ديناميكي


  1. نستخدم أنماط نص النظام الديناميكي بدلاً من الأنماط الثابتة.
  2. اختياريًا ، قم بتمكين علامة اختيار "ضبط الخط تلقائيًا" على الملصقات في لوحات القصة. أو ، إذا كانت التسمية في الزر أو تم إنشاؤها من خلال التعليمات البرمجية ، فإننا adjustsFontForContentSizeCategory المعلمة الخاصة بها adjustsFontForContentSizeCategory .
  3. نقوم بتعليم الواجهة لتمتد إلى أحجام الخطوط المختلفة:
    - نحن نستخدم الحساب التلقائي لأحجام الخلايا حيث يمكننا.
    - حيث لا يمكننا - نحصل على إعدادات حجم الخط الحالية traitCollectionDidChange للتغييرات في طريقة traitCollectionDidChange .
  4. نحصل على واجهة مستحيلة الاستخدام.




نحن نغير الواجهة بحيث يمكن استخدامها


نعود ونبدأ في التفكير في كيفية القيام بكل شيء بشكل جيد.

استخدام صحيح المكان في القائمة


الآن هناك الكثير من المساحة الفارغة تحت صورة البيتزا. دعونا نحاول وضع صورة فوق الاسم: بهذه الطريقة ستصبح أكبر ، وستختفي المساحة الفارغة. للقيام بذلك ، نقوم بلف الصورة UIStackView الحاوية مع كل شيء آخر في UIStackView ، وبعد ذلك سنقوم UIStackView اتجاه عرض المكدس إذا لزم الأمر.



ليس لدينا فواصل بين عناصر القائمة ، ولهذا السبب عندما يكون الحجم كبيرًا ، تبدأ الخلايا في "الالتصاق معًا" وتكون علامة سعر البيتزا قريبة جدًا من صورة البيتزا التالية. دعنا نحاول إضافة فاصل.



ليس هذا. أولاً ، يبدو الأمر كذلك. ثانياً ، سيكون من الصعب رؤية الأشخاص الذين يعانون من ضعف في الرؤية. حتى لو طلاؤها من الرمادي إلى الأسود.

نقوم بإزالته مرة أخرى ونحاول فقط زيادة الإنترنت بين الخلايا.



الآن بعد ذلك.

المجموع الفرعي: استخدام مساحة أكبر ، تقفز العينين أقل من سطر إلى آخر ، أصبحت القراءة أسهل.

نحن تحسين تمتد وإزالة


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



أنا أنظر إلى كل هذا وأدرك أن صورة البيتزا ، بالطبع ، ضخمة للغاية. دعونا نحاول إخفاءه ، ربما بدون صور يمكنك العيش بها.



بشكل عام ، لم تفقد القائمة التي لا تحتوي على صور الكثير من المعلومات ، ولكن الآن يتداخل عنصر قائمة واحد دائمًا مع شاشة iPhone 6S. لكنه أصبح أقل جاذبية ، Drool لا يتدفق عند التمرير. هذا. الآن ، دعنا نترك الأمر هكذا ، فكر جيدًا وربما أعيد الصورة لاحقًا.

لا تنس أن تحقق "العيش"


الآن الفئات. بشكل عام ، حتى مع النهج الأول اتضح أنه مقبول. بدوره على واحدة جديدة.



حاولت تصفح القائمة والتبديل بين الفئات. ومع ذلك ، فقد تبين أنها سيئة: كل شيء ينهار في العمل. عند التمرير عبر القائمة ، تتغير الفئات تلقائيًا ، وفي هذه المسامير الكبيرة تجذب الانتباه كثيرًا.

دعنا نستبدل UICollectionView مع زر سوف يتصل بـ UIActionSheet .



Vooot. الآن يمكنك أن تأخذ لوحة أعلى ، حيث المدينة والأسهم والعنوان ورمز الترويجية.

لا تنسى طوابير طويلة جدا


أولاً ، دعنا ننتقي من المدينة. لا يوجد شيء معقد مع الخط الموجود في الزر ، ولكن من المثير للاهتمام تعليم "المثلثات" لتنمو مع الخط. في حالتنا ، تم صنع المثلث رمزًا في الزر ، والذي يتم نقله إلى الجانب الأيمن من خلال CGAffineTransform . خيار آخر هو جمع NSAttributedString من النص وأيقونة المثلث ، ثم تغذيته جميعًا إلى الزر. لتطبيع الأيقونة ، يمكنك استخدام صورة متجهة ، والتي يجب أن تكون بالضرورة في الأصول مع تحديد خانة الاختيار الاحتفاظ ببيانات المتجه.


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

نحن الآن نمد الروبل بالرودو ، كل شيء بسيط:



والسؤال المطروح الآن هو: ماذا سيحدث إذا كان اسم المدينة طويلًا ولدينا العديد من روبل الدودو؟ من الناحية النظرية ، تحتاج إلى اختصار اسم المدينة. تذكر ما قلته عن الخيار الثاني لإضافة مثل هذا الرمز إلى زر ، من خلال NSAttributedString ؟ لقد جربت الآن ، وهناك مشكلة أنه عندما نقوم بتقليل العنوان ، يختفي رمز المثلث ، لأنه الآن جزء من العنوان. Shtosh. سيتعين علينا إعادة منطق نقل الأيقونة عبر التحويلات.
إذا كنت تعرف طريقة ملائمة لنقل الأيقونة الموجودة في الزر إلى الجانب الأيمن وقياسها مع الخط الموجود في الرأس - فتجاهلها في التعليقات ، من فضلك.

كرام في


وأخيرا الأسهم. هنا تحتاج إلى الجلوس والتفكير. يمكن أن يكون العنوان طويلًا وحتى الآن لا يصلح في بعض الأحيان لسطر واحد. على حجم كبير ، وقال انه لن يصلح بشكل جيد على الإطلاق. إذا قمت بتصنيع اللوحة البرتقالية العليا وتمكنت من احتواء عنوان الحركة بحجم كبير على عدة أسطر ، فستتناول الكتلة العلوية نصف الشاشة حتى على أجهزة iPhone الكبيرة ، ولن تضطر إلى تذكر حوالي 4S. هذا ليس هو الحال. يمكنك اللعب باستخدام تخطيط داخل مربع الإجراء: اجعل مربع الصورة ، واتخاذ المكان الشاغر كعنوان. لكن الصور الخاصة بالأسهم يتم تخصيصها لتنسيق معين ولن يتم عرضها بشكل صحيح في تنسيق آخر. هذا مستحيل.

مجمع.

لذلك ، ولكن يمكنك مرة أخرى إزالة الصور تمامًا وتناول المكان بالكامل بعنوان رئيسي.



نعم هو كذلك. سلّم الحكة لتلوين الخلفية تحت عنوان الإجراء ، لكن هذا سيؤثر سلبًا على قابلية القراءة. ونحن ، مثل ، نحاول تحسينه. لذلك نحن لا نرسم أي شيء وننتقل إلى الزرين المتبقيين حول العنوان والرموز الترويجية.

نحن نعمل مع قيود صارمة


العناوين في هذه الأزرار غير قابلة للاختزال. ولكن إذا لم يتم تخفيضها ، فستتسلل الأزرار إلى بعضها البعض. ونعم ، لا يمكنك إخفاء هذه الأزرار.

عندما أعدت المخزون ، لم أكن أريد زيادة ارتفاع اللوحة البرتقالية العليا. يبدو أن لديك ل. من الجيد أنهم لم يزيدوه في ذلك الوقت ، وإلا فلن يكون هناك عدوًا بشكل عام. بشكل عام ، سأختار سطرًا واحدًا لكل زر.



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

دعنا نقارن النهج الأول بالنتيجة النهائية:



قارن الآن بين "السابق" و "بعد" بمحاكاة للرؤية السيئة:



لا تخف من تغيير الواجهة وعناصر التحكم. لا حرج في رؤية شخص ما لزر آخر أو على سبيل المثال شريط تمرير. وهي ليست قاتلة إذا كان شخص ما لا يرى شيئا أو إذا كان العنوان مختلفا.
ولم نلمس UITabBarController ، لأنه مع وجود حجم كبير للنص ، يمكن أن يظهر خارج المربع بنقرة طويلة الرمز وعنوان علامة التبويب بنفس الطريقة التي يعرض بها iOS التغير في الحجم.

نظهر كيف يعمل كل شيء في الداخل


يتم تخصيص كل مكون واجهة مستخدم منطقي في تطبيق Dodo Pizza iOS إلى UIViewController منفصل. كل وحدة تحكم من هذا القبيل لديها UIView المخصصة لملف منفصل. يمكنك قراءة المزيد حول هذا الموضوع في مقالاتنا:

تحكم ، أعتبر سهل! نحن نخرج الكود في UIView
تحكم البصل. نحن تقسيم الشاشات إلى أجزاء

سهّلت إزالة مكونات واجهة المستخدم المنطقية في UIViewController منفصلة مهمة تعديل الواجهات إلى حالات مختلفة. نوصيك بتجربة هذا النهج ، حتى لو لم تكن تخطط لإضافة دعم Dynamic Type - من الأسهل التحكم في حالة الشاشات: الاستجابة للتغيرات في الترخيص والحقوق والأدوار وما إلى ذلك.

لذلك هنا. نضيف طبقة إضافية بين مكون واجهة المستخدم هذا والحاوية الأصل. لدينا يسمى StateViewController .


تقوم وحدة التحكم في القائمة بدمج وحدة التحكم في الحالة ، وتقوم بالفعل بتضمين collection - أو التحكم في button .

يوضح StateViewController هذا أو ذاك المكون UI بناءً على الموقف.

للقيام بذلك ، يحتاج StateViewController إلى معرفة StateViewController إذا لزم الأمر.

في هذا المثال ، سوف يقوم StateViewController اختيار الفئات في القائمة من المجموعة إلى الزر والعكس. وفي حالة العرض "العادي" ، وفي حالة العرض للأشخاص ذوي الإعاقات البصرية ، يجب أن يكون المحدد قادراً على فعل نفس الأشياء:

  • عرض قائمة الفئات.
  • تسليط الضوء على الفئة المحددة.
  • تحديث قائمة الفئات.
  • أبلغ أن الفئة "خرجت".

تشعر هذه الرائحة الرائعة من سجلات القليل الطازجة؟ و ، لا ، هذا هو فريق من api المحمول يسلم البيتزا. 5 دقائق استراحة.

2 شرائح في وقت لاحق
"... حسنًا ، نلتف مكوناتنا مثل ذلك لتحديد فئات في البروتوكولات ، وهم على الفور!"
تلميح: قم بتشغيل Accessibility Inspector للتحقق بسهولة من استجابة الواجهة للتغيرات في إعدادات التجانب الديناميكي. للقيام بذلك ، في Xcode المفتوح ، انقر فوق Xcode → أداة المطور المفتوحة → Accessibility Inspector ، حدد جهاز محاكاة في الجهاز وانتقل إلى علامة التبويب الأخيرة

تلميح آخر: أخرج عنصر التحكم الديناميكي taip على iPhone (وليس على جهاز محاكاة) إلى "مركز التحكم" لتغيير حجم النص بسهولة وبسرعة. للقيام بذلك ، على جهاز iPhone ، انتقل إلى الإعدادات ← مركز التحكم ← تخصيص عناصر التحكم وإضافة حجم النص.

أطلقنا على محدد الفئة المعتادة CategoriesCollectionViewController ، ولضعاف البصر - CategoriesButtonViewController . ويطلق على البروتوكول المشترك الخاص بهم CategoriesPickerProtocol . وحدة تحكم الحالة العامة هي CategoriesStateViewController .

نحن نصف الحالات المحتملة في CategoriesStateViewController بنا.

 private enum State { case collection, button } 

نعلمه إظهار وحدة التحكم المطلوبة لكل ولاية:

 private var state: State = .collection { didSet { if state != oldValue { updateViewController(for: state) } } } private func updateViewController(for state: State) { let viewController = self.viewController(for: state) self.updateController(with: viewController) } private func viewController(for state: State) { switch state { case .collection: return CategoriesCollectionViewController.instantiateFromStoryboard() case .button: return CategoriesButtonViewController.instantiateFromStoryboard() } } 

instantiateFromStoryboard() - طريقة من امتداد مكتوب ذاتيًا إلى وحدة تحكم في طريقة العرض ، تقوم بإنشاء مثيل وحدة تحكم من لوحات القصة إذا كان لديهم نفس الاسم. الكود موجود في الكود المصدري في نهاية المقال.

 override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) self.updateStateToCurrentContentSize() } private func updateStateToCurrentContentSize() { let contentSize = self.traitCollection.preferredContentSizeCategory self.updateState(to: contentSize) } private func updateState(to contentSize: UIContentSizeCategory) { self.state = contentSize.isAccessibilityCategory ? .button : .collection } 

وصفنا بروتوكول CategoriesPickerProtocol ، بإضافة بروتوكولين آخرين في وقت واحد: للمندوب ولبيانات البيانات.

 protocol CategoriesPickerProtocol where Self: UIViewController { var datasource: CategoriesDatasource? { get set } var delegate: CategoriesDelegate? { get set } func select(_ category: ProductCategoryModule.ProductCategoryViewModel) func updateCategories() var selectedCategory: ProductCategoryModule.ProductCategoryViewModel? { get } } protocol CategoriesDatasource: class { var categories: [ProductCategoryModule.ProductCategoryViewModel] { get } func index(of category: Product.ProductCategory) -> Int } protocol CategoriesDelegate: class { func productCategoriesView(_ categoriesPicker: CategoriesPickerProtocol, didSelect category: ProductCategoryModule.ProductCategoryViewModel) } 

لا يوجد أي معنى لإظهار التطبيق ، إنه فقط يعرض كل لاعب عرض الفئات والتقارير إلى الأعلى.

يمكن العثور على مثال تفصيلي لاستخدام وحدات تحكم الحالة في taype الديناميكي في repo الخاص بي على GitHub .

بالمناسبة ، نحن نتوسع

Source: https://habr.com/ru/post/ar452226/


All Articles