BoxView - autolayout مفيد لنظام التشغيل iOS

أرغب في مشاركة مكتبة لبناء واجهة مستخدم لتطبيقات iOS القائمة على التشغيل التلقائي بكفاءة.



على الرغم من ظهور SwiftUI ، إلا أن أهمية autolayout تتناقص بسرعة ، بينما لا تزال هذه الآلية مستخدمة بنشاط ، ويمكن أن تكون المكتبة مفيدة لأولئك الذين ينشئون (أو يغيرون) واجهة المستخدم مباشرة في التعليمات البرمجية.



هذه الطريقة في إنشاء واجهة لها عدد من العيوب التي تحد من استخدامها:



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


يمكن حل المشكلة الأولى بسهولة عن طريق لف الطرق القياسية لإنشاء قيود في شيء أكثر إنسانية. وقد تم تنفيذه بشكل جيد بالفعل ، على سبيل المثال ، في SnapKit و TinyConstictions ومكتبات أخرى مماثلة.



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

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



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



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



كمثال ، ضع في اعتبارك إنشاء تسجيل دخول بسيط للنموذج باستخدام BoxView (يتوفر رمز المثال الكامل مع وصف تفصيلي خطوة بخطوة في مشروع BoxViewExample على github ).



صورة


تكفي بضعة أسطر من التعليمات البرمجية لإنشاء مثل هذا التخطيط على BoxView:



        nameBoxView.items = [nameImageView.boxed.centerY(), nameField.boxed]
        passwordBoxView.items = [passwordImageView.boxed.centerY(), passwordField.boxed]
        boxView.insets = .all(16.0)
        boxView.spacing = 20.0
        boxView.items = [
            titleLabel.boxed.centerX(padding: 30.0).bottom(20.0),
            nameBoxView.boxed,
            passwordBoxView.boxed,
            forgotButton.boxed.left(>=0.0),
            loginButton.boxed.top(30.0).left(50.0).right(50.0),
        ]


يتم إنشاء BoxItem من أي UIView باستخدام المتغير المحاصر ، وبعد ذلك يمكن ضبطه على الحشو على 4 جوانب ، والمحاذاة ، والأحجام المطلقة أو النسبية.



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



صورة


وعلى الرغم من أن الرسالة يجب أن تكون "مضمنة" في التخطيط الحالي ، إلا أنها لا تتطلب حتى تغيير الرمز الحالي!



    func showErrorForField(_ field: UITextField) {
        errorLabel.frame = field.convert(field.bounds, to: boxView)
        let item = errorLabel.boxed.top(-boxView.spacing).left(errorLabel.frame.minX - boxView.insets.left)
        boxView.insertItem(item, after: field.superview, z: .back)
        boxView.animateChangesWithDurations(0.3)
    }
    
    @objc func onClickButton(sender: UIButton) {
        for field in [nameField, passwordField] {
            if field.text?.isEmpty ?? true {
                showErrorForField(field)
                return
            }
        }
        // ok, can proceed with login
    }
    
    @objc func onChangeTextField(sender: UITextField) {
        errorLabel.removeFromSuperview()
        boxView.animateChangesWithDurations(0.3)
    }


يدعم BoxView جميع أدوات autolayout: المسافة بين العناصر والأحجام المطلقة والنسبية والأولويات ودعم لغات RTL. بالإضافة إلى UIView ، كائنات غير مرئية - يمكن أيضًا استخدام UILayoutGuides كعناصر تخطيط. يمكن أيضًا استخدام تخطيط المرن. بالطبع ، فإن مخطط التصميم نفسه ، في شكل نظام من المداخن المضمنة لـ UIView ، لا يغطي 100 ٪ جميع الخيارات التي يمكن تصورها للترتيب النسبي للعناصر ، ولكن هذا ليس مطلوبًا. لا بأس في ذلك بالنسبة للغالبية العظمى من واجهات المستخدم النموذجية ، وبالنسبة للحالات الأكثر غرابة ، يمكنك دائمًا إضافة القيود الإضافية المقابلة بأي طريقة أخرى. يتم تضمين العديد من طرق المساعدة ، على سبيل المثال ، لإنشاء قيود نسبة العرض إلى الارتفاع ، في المكتبة.



مثال صغير آخرمتاح على github (~ 100 سطر من التعليمات البرمجية!) يوضح استخدام نظام BoxView المتداخل بالاقتران مع طرق إعداد القيد الأخرى ، بالإضافة إلى تغيير متحرك في إعدادات BoxView.



صورة


مشروع BoxView على جيثب



All Articles