UIView
hierarchy. The tasks of each view
: to create elements, set up, decompose into places, animate. This is evident from the methods that are in the UIView: addSubview(), drawRect(), layoutSubviews().
class UIView: addSubview(), drawRect(), layoutSubviews().
UIViewController
class, you can see that he is in control of view:
loads, reacts to screen loading and user actions, shows new screens. Often the code that needs to be in a UIView
is written in subclasses of UIViewController
, which makes it too large. Separate it.UIViewController
life cycle begins with loadView()
. A simplified implementation looks like this: // CustomViewController.swift func loadView() { self.view = UIView() }
super.loadView()
no need to call! // CustomViewController.swift override func loadView() { self.view = CustomView() }
// CustomView.swift final class CustomView { let square: UIView = UIView() init() { super.init() square.backgroundColor = .red addSubview(square) } }
CustomView,
add it to the hierarchy, set the .frame
. The .view
property will be the class we need: // CustomViewController.swift print(view) // CustomView
UIView
. Let's fix this with a type conversion: // CustomViewController.swift func view() -> CustomView { return self.view as! CustomView }
CustomView
variables: // CustomViewController.swift func viewDidLoad() { super.viewDidLoad() view().square // }
Ruslan Kavetsky proposed to remove code duplication using protocol extension:
protocol ViewSpecificController { associatedtype RootView: UIView } extension ViewSpecificController where Self: UIViewController { func view() -> RootView { return self.view as! RootView } }
For each new controller, you only need to specify the protocol and subclass for itsUIView
throughtypealias
:
// CustomViewController.swift final class CustomViewController: UIViewController, ViewSpecificController { typealias RootView = CustomView func viewDidLoad() { super.viewDidLoad() view().square // } }
// CustomView.swift init() { super.init() backgroundColor = .lightGray addSubview(square) }
layoutSubviews()
method. It is called every time the view
size changes, so you can rely on the bounds
size for correct calculations: // 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
controls private, but I manage them through public variables or “in the knowledge” functions. Easier by example: // CustomView.swift private let square = UIView() var squarePositionIsValid: Bool { didSet { square.backgroundColor = squarePositionIsValid? .green : .red } } func moveSquare(to newCenter: CGPoint) { square.center = newCenter }
viewDidLoad()
empty. If you create a view
in code, then you need to bind their actions through the target-action pattern, add a UIGestureRecognizer
or associate delegates.view
can be configured through Interface Builder (hereinafter IB).view
object (not the controller) and set its class. Write your own loadView()
not necessary, the controller will do it himself. But UIView
still have to UIView
type.view
, the Assistant Editor will recognize the UIView
class and offer it as the second file in Automatic mode. So you can transfer IBOutlet
to view
.CustomView
class manually, write IBOutlet
. You can now drag the marker and hover over an item in IB.init()
, but when working with IB, access to IBOutlet
appears only after loading the interface from the UIStoryboard
in the awakeFromNib()
method: // CustomView.swift func awakeFromNib() { super.awakeFromNib() square.layer.cornerRadius = 8 }
UIViewController
Notification
responseUIViewController
controls only the interface. Everything related to business logic should be taken out of the controller, but this is a choice: MVP, VIPER, etc.UIView
type. To do this, declare a property with the required class, override setter
and getter
, specifying the class: // CustomViewController.m @interface CustomViewController @property (nonatomic) CustomView *customView; @end @implementation - (void)setView:(CustomView *)view{ [super setView:view]; } - (CustomView *)view { return (CustomView *)super.view; } @end
view
, but encapsulation makes it easy to interact and read the code. Sometimes the view
can be reused with another controller. For example, different controllers for the iPhone and iPad react differently to the appearance of the keyboard, but this does not change the view
code in any way.UIViewController
!Source: https://habr.com/ru/post/432718/
All Articles