On this nice iOS Auto Format tutorial I will train you learn how to assist rotation, use constraints, work with layers, animate nook radius.
UIKit
Rotation assist
In case your software goes to assist a number of gadget orientations, it is best to implement the next strategies inside your view controller.
class ViewController: UIViewController {
override var shouldAutorotate: Bool {
return false
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
return .portrait
}
}
Clearly you’ll be able to change the return values to assist not simply portrait, however panorama mode as properly. That is fairly straightforward, nevertheless in case your controller is embedded inside a navigation or a tab bar controller the rotation stops working. On this case, it’s important to subclass the UINavigationController, and it’s important to return the right values from the highest view controller.
class NavigationController: UINavigationController {
override var shouldAutorotate: Bool {
if let shouldRotate = self.topViewController?.shouldAutorotate {
return shouldRotate
}
return tremendous.shouldAutorotate
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if let orientation = self.topViewController?.supportedInterfaceOrientations {
return orientation
}
return tremendous.supportedInterfaceOrientations
}
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
if let orientation = self.topViewController?.preferredInterfaceOrientationForPresentation {
return orientation
}
return tremendous.preferredInterfaceOrientationForPresentation
}
}
The identical logic applies when you have a UITabBarController, however as a substitute of the highest view controller, it’s important to use the selectedIndex, and return the properties primarily based on the chosen view controller.
class TabBarController: UITabBarController {
override var shouldAutorotate: Bool {
if let viewController = self.viewControllers?[self.selectedIndex] {
return viewController.shouldAutorotate
}
return tremendous.shouldAutorotate
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if let viewController = self.viewControllers?[self.selectedIndex] {
return viewController.supportedInterfaceOrientations
}
return tremendous.supportedInterfaceOrientations
}
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
if let viewController = self.viewControllers?[self.selectedIndex] {
return viewController.preferredInterfaceOrientationForPresentation
}
return tremendous.preferredInterfaceOrientationForPresentation
}
}
This fashion your embedded controller can management the supported orientations. Oh, by the best way you should utilize this technique to cahnge the standing bar model.
Constraints
With a view to perceive constraints and the present state of the Auto Format engine, we should always return to in time and begin the story from the start.
Springs and struts
Keep in mind the primary iPhone? One display screen to rule all of them! 320×480, no constraints, no adaptivity, simply frames and bounds. Positioning views on a hard and fast measurement canvas is totally a no brainer, right here is an instance.
class ViewController: UIViewController {
weak var sq.: UIView!
var squareFrame: CGRect {
let midX = self.view.bounds.midX
let midY = self.view.bounds.midY
let measurement: CGFloat = 64
return CGRect(x: midX-size/2, y: midY-size/2, width: measurement, top: measurement)
}
override func loadView() {
tremendous.loadView()
let sq. = UIView()
self.view.addSubview(sq.)
self.sq. = sq.
}
override func viewDidLoad() {
tremendous.viewDidLoad()
self.sq..backgroundColor = .yellow
}
override func viewDidLayoutSubviews() {
tremendous.viewDidLayoutSubviews()
self.sq..body = self.squareFrame
}
}
With the viewDidLayoutSubviews technique it is tremendous handy to assist rotation, I simply need to re-calculate the body of the view each time if the bounding rectangle modifications. You may suppose hey, that is straightforward, however what occurs if it’s important to assist numerous gadget sizes?
Do the mathematics!
For one single object it is really easy to make the calculations, however normally you’ve gotten multiple view on display screen. These views can have relations to one another, and a basic math trick can lead you to an entire chaos of body calculations, do you even like arithmetic? There should be a greater manner!
Auto Format
With iOS6 Apple introduced us the holy grail of structure applied sciences. It was the right successor of the earlier system. Everybody adopted it quick, that is why Apple engineers utterly eliminated body primarily based structure APIs within the subsequent launch… #justkidding
Aside from the joke, it was the start of a brand new period, increasingly more gadgets have been born, and with Auto Format constraints it was tremendous straightforward to keep up views. Now we should always refactor the earlier instance with structure constraints.
class ViewController: UIViewController {
weak var sq.: UIView!
override func loadView() {
tremendous.loadView()
let sq. = UIView()
self.view.addSubview(sq.)
sq..translatesAutoresizingMaskIntoConstraints = false
self.view.addConstraints([
NSLayoutConstraint(item: square, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1.0, constant: 64),
NSLayoutConstraint(item: square, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1.0, constant: 64),
NSLayoutConstraint(item: square, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: square, attribute: .centerY, relatedBy: .equal, toItem: self.view, attribute: .centerY, multiplier: 1.0, constant: 0),
])
self.sq. = sq.
}
override func viewDidLoad() {
tremendous.viewDidLoad()
self.sq..backgroundColor = .yellow
}
}
As you’ll be able to see we need not manually calculate the body of the view, nevertheless creating constraints programmatically shouldn’t be so handy. That is why Apple made the constraint Visible Format Language.
VFL = WTF?
Truly this VFL is so unhealthy that I do not even need to demo it, however anyway…
class ViewController: UIViewController {
weak var sq.: UIView!
override func loadView() {
tremendous.loadView()
let sq. = UIView()
self.view.addSubview(sq.)
sq..translatesAutoresizingMaskIntoConstraints = false
let views: [String:Any] = ["view": self.view, "subview": square]
let vertical = NSLayoutConstraint.constraints(withVisualFormat: "V:[view]-(<=1)-[subview(==64)]", choices: .alignAllCenterX, metrics: nil, views: views)
let horizontal = NSLayoutConstraint.constraints(withVisualFormat: "H:[view]-(<=1)-[subview(==64)]", choices: .alignAllCenterY, metrics: nil, views: views)
self.view.addConstraints(vertical)
self.view.addConstraints(horizontal)
self.sq. = sq.
}
override func viewDidLoad() {
tremendous.viewDidLoad()
self.sq..backgroundColor = .yellow
}
}
God forbid the engineer who invented this black magic. 🙂
In order you’ll be able to see we positively have an issue with constraints. Creating all of your constraints sucks, no less than it’ll value many many traces of code. After all you should utilize the magical interface builder, however the place’s the enjoyable if you happen to simply drag traces?
Creating constraints programmatically is not any higher than calculating frames, it’s going to lead you to the identical stage of complexity and even worse, this is the reason so many third occasion frameworks got here alive and ultimately Apple issued the issue as properly.
I’ve a tremendous article about mastering Auto Format anchors, I extremely advocate studying it if you wish to get conversant in anchors. 📖
Anchors
Anchors have been born as a result of Auto Format had some development flaws.
The NSLayoutAnchor class is a manufacturing facility class for creating NSLayoutConstraint objects utilizing a fluent API. Use these constraints to programatically outline your structure utilizing Auto Format.
class ViewController: UIViewController {
weak var sq.: UIView!
override func loadView() {
tremendous.loadView()
let sq. = UIView()
self.view.addSubview(sq.)
sq..translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
square.widthAnchor.constraint(equalToConstant: 64),
square.heightAnchor.constraint(equalToConstant: 64),
square.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
square.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),
])
self.sq. = sq.
}
override func viewDidLoad() {
tremendous.viewDidLoad()
self.sq..backgroundColor = .yellow
}
}
See, completely rocks! Anchors are one of the best ways of utilizing for Auto Format constraints.
Adaptive structure
For those who have a look at the present state of built-in apps offered by Apple, you’ll be able to see that solely a few of them are responsive / adaptive. Basically, apps that utilizing assortment views are simpler to adapt for greater screens, or completely different gadget orientations.
ALWAYS use assortment views
Besides if it is only one view on the middle of the display screen, it is best to construct up your consumer interfaces utilizing assortment views. It offers you reusability, decrease reminiscence overhead, scrolling and lots of extra advantages. You do not even need to calculate the silly index pahts in case you are utilizing my CollectionView micro framework.
Auto Format with layers
Auto Format is nice, however typically it’s important to work with layers instantly. Now on this state of affairs, you continue to need to do some calculations. You’ll be able to simply override the bounds property and replace frames within the didSet block in case you are coping with a view subclass.
override var bounds: CGRect {
didSet {
self.gradientLayer.body = self.bounds
}
}
An alternative choice is to override the viewDidLayoutSubviews technique contained in the view controller, and set the body of the layer primarily based on the brand new bounds.
override func viewDidLayoutSubviews() {
tremendous.viewDidLayoutSubviews()
self.gradientView.gradientLayer.body = self.gradientView.bounds
}
It’s also possible to use plain previous Key-Worth Observing to look at an objet’s bounds property and replace the body of the layer in accordance with that.
self.addObserver(self, forKeyPath: "bounds", choices: .new, context: nil)
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard keyPath == "bounds" else {
return tremendous.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
}
self.gradientLayer.body = self.bounds
}
deinit {
self.removeObserver(self, forKeyPath: "bounds")
}
Animating nook radius
Initially if you wish to animate a view whereas utilizing constraint primarily based layouts, it’s important to do one thing like this.
self.widthConstraint.fixed = 64
UIView.animate(withDuration: 0.5, animations: {
self.view.layoutIfNeeded()
}, completion: nil)
Now if you wish to animate the nook radius of a view, you’ll be able to at all times use the standard manner, and set the cornerRadius property of the layer on a bounds change.
However, we have this fancy new UIViewPropertyAnimator API since iOS 10.
self.imageView.layer.cornerRadius = 16
UIViewPropertyAnimator(period: 2.5, curve: .easeInOut) {
self.imageView.layer.cornerRadius = 32
}.startAnimation()
It is fairly easy, you’ll be able to even apply a cornerMask to spherical simply a number of the corners. The layer primarily based structure examples are contained in the offered supply code for the article alongside with an entire pattern for every Auto Format approach. You’ll be able to obtain or clone it from the The.Swift.Dev tutorials repository.