تحكم ، أعتبر سهل! نحن نخرج الكود في UIView

هل لديك UIViewController كبيرة؟ بالنسبة للكثيرين ، نعم. من ناحية ، يعمل مع البيانات ، من ناحية أخرى - مع الواجهة.

يتم وصف مهام فصل المنطق عن الواجهة في مئات المقالات حول الهندسة المعمارية: MVP ، MVVM ، VIPER. إنها تحل مشكلة تدفق البيانات ، لكن لا تجيب على سؤال حول كيفية التعامل مع الواجهة: في مكان واحد يبقى إنشاء عناصر ، تخطيط ، تهيئة ، معالجة المدخلات والرسوم المتحركة.

دعونا نفصل العرض عن وحدة التحكم ونرى كيف يساعدنا loadView ().



واجهة التطبيق لنظام التشغيل iOS هي التسلسل الهرمي UIView . مهام كل view : إنشاء عناصر ، تخصيص ، ترتيب في الأماكن ، تنشيط. يمكن ملاحظة ذلك من خلال الطرق الموجودة في فئة UIView: addSubview(), drawRect(), layoutSubviews().

إذا نظرت إلى أساليب فئة UIViewController ، يمكنك أن ترى أنها تدير view: تحميله ، ويستجيب لتحميل الشاشات وإجراءات المستخدم ، ويظهر الشاشات الجديدة. غالبًا ما تكون الشفرة التي يجب أن تكون في UIView ، UIView في فئات فرعية من UIViewController ، مما يجعلها كبيرة جدًا. افصلها

loadView ()


تبدأ دورة حياة loadView() بـ loadView() . يبدو التنفيذ المبسط كما يلي:

 // CustomViewController.swift func loadView() { self.view = UIView() } 

يمكننا تجاوز الطريقة وتحديد فصلنا.

لا يحتاج super.loadView() ليتم استدعاؤه!

 // CustomViewController.swift override func loadView() { self.view = CustomView() } 

تطبيق CustomView.swift
 // CustomView.swift final class CustomView { let square: UIView = UIView() init() { super.init() square.backgroundColor = .red addSubview(square) } } 


سيتم تحميل CustomView, وإضافته إلى التسلسل الهرمي ، فضح. .frame . .view الخاصية .view هي الفئة التي نحتاجها:

 // CustomViewController.swift print(view) // CustomView 

ولكن في حين أن المترجم لا يعرف عن الفصل ويعتقد أن هناك UIView العادي. دعونا إصلاح هذا مع وظيفة نوع يلقي:

 // CustomViewController.swift func view() -> CustomView { return self.view as! CustomView } 

يمكنك الآن رؤية متغيرات CustomView :

 // CustomViewController.swift func viewDidLoad() { super.viewDidLoad() view().square //  } 

تبسيط مع المرتبطة
اقترح Ruslan Kavetsky إزالة ازدواجية الرمز باستخدام توسيع البروتوكول:

 protocol ViewSpecificController { associatedtype RootView: UIView } extension ViewSpecificController where Self: UIViewController { func view() -> RootView { return self.view as! RootView } } 

لكل وحدة تحكم جديدة ، تحتاج فقط إلى تحديد البروتوكول typealias الفرعية لـ UIView خلال typealias :

 // CustomViewController.swift final class CustomViewController: UIViewController, ViewSpecificController { typealias RootView = CustomView func viewDidLoad() { super.viewDidLoad() view().square //  } } 

رمز في فئة فرعية من UIView


إنشاء وتكوين الضوابط


يمكن تعيين الخطوط والألوان والثوابت والتسلسل الهرمي مباشرةً في مُنشئ CustomView:

 // CustomView.swift init() { super.init() backgroundColor = .lightGray addSubview(square) } 

تخطيطالمقابلات الشخصية ()


أفضل مكان للتخطيط اليدوي هو طريقة layoutSubviews() . يطلق عليه في كل مرة يتم تغيير حجم view ، لذلك يمكنك الاعتماد على حجم bounds للحسابات الصحيحة:

 // CustomView.swift override func layoutSubviews() { super.layoutSubviews() square.frame = CGRect(x: 0, y: 0: width: 200, height: 200) square.center = CGPoint(x: bounds.width / 2, y: bounds.height / 2) } 

الضوابط الخاصة والممتلكات العامة


إذا كان هناك وقت ، فعندئذ اجعل عناصر التحكم في property خاصة ، لكنني أديرها من خلال المتغيرات العامة أو الوظائف "في مجال المعرفة". مثال أبسط:

 // CustomView.swift private let square = UIView() var squarePositionIsValid: Bool { didSet { square.backgroundColor = squarePositionIsValid? .green : .red } } func moveSquare(to newCenter: CGPoint) { square.center = newCenter } 

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

ما تبقى في viewDidLoad ()؟


إذا كنت تستخدم Interface Builder ، فغالبًا ما يكون viewDidLoad() فارغًا. إذا قمت بإنشاء view في التعليمات البرمجية ، فأنت بحاجة إلى ربط إجراءاتها من خلال نمط عمل الهدف ، أو إضافة UIGestureRecognizer أو ربط المفوضين.

للتخصيص من خلال واجهة البناء


يمكن تكوين الفئة الفرعية view من خلال Interface Builder (يشار إليها فيما بعد بـ IB).

تحتاج إلى تحديد كائن view (وليس وحدة التحكم) وتعيين فئتها. ليس من الضروري أن تكتب loadView() الخاص بك ، وحدة التحكم سوف تفعل ذلك بنفسها. ولكن لا يزال يتعين عليك UIView نوع UIView .



IBOutlet في UIView


إذا قمت بتحديد عنصر التحكم داخل view ، UIView Assistant Editor على فئة UIView أنها الملف الثاني في الوضع التلقائي. حتى تتمكن من نقل IBOutlet view .



إن لم يكن يعمل
افتح فئة CustomView يدويًا ، اكتب IBOutlet . يمكنك الآن سحب علامة الماوس وتحريكها فوق عنصر في IB.



إذا قمت بإنشاء واجهة في التعليمات البرمجية ، فإن كل الكائنات يمكن الوصول إليها بعد init() ، ولكن عند العمل مع IB ، يظهر الوصول إلى IBOutlet فقط بعد تحميل الواجهة من UIStoryboard في طريقة awakeFromNib() :

 // CustomView.swift func awakeFromNib() { super.awakeFromNib() square.layer.cornerRadius = 8 } 

IBAction في UIViewController


لذوقي ، يجب أن تترك وحدة التحكم جميع إجراءات المستخدم. من المعيار:

  • الهدف العمل من الضوابط
  • تفويض التنفيذ في UIViewController
  • تنفيذ كتلة
  • رد الفعل على Notification

في هذه الحالة ، يتحكم UIViewController في الواجهة فقط. يجب إخراج كل ما يتعلق بمنطق العمل من وحدة التحكم ، ولكن هذا اختيار: MVP ، VIPER ، إلخ.

الهدف ج


في Objective-C ، يمكنك استبدال نوع UIView بالكامل. للقيام بذلك ، قم بتعريف الخاصية مع الفئة المرغوبة ، وتجاوز setter و getter ، مع تحديد الفئة:

 // CustomViewController.m @interface CustomViewController @property (nonatomic) CustomView *customView; @end @implementation - (void)setView:(CustomView *)view{ [super setView:view]; } - (CustomView *)view { return (CustomView *)super.view; } @end 

النهاية


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

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

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

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


All Articles