HomeiOS DevelopmentMastering iOS auto format anchors programmatically from Swift

Mastering iOS auto format anchors programmatically from Swift


Creating views and constraints programmatically

To start with I might wish to recap the UIViewController life cycle strategies, you might be may aware of a few of them. They’re being known as within the following order:

  • loadView
  • viewDidLoad
  • viewWillAppear
  • viewWillLayoutSubviews
  • viewDidLayoutSubviews
  • viewDidAppear

Within the pre-auto format period, you needed to do your format calculations contained in the viewDidLayoutSubviews methodology, however since this can be a professional auto format tutorial we’re solely going to concentrate on the loadView & viewDidLoad strategies. 🤓

These are the essential guidelines of making view hierarchies utilizing auto format:

  • By no means calculate frames manually by your self!
  • Initialize your views with .zero rect body
  • Set translatesAutoresizingMaskIntoConstraints to false
  • Add your view to the view hierarchy utilizing addSubview
  • Create and activate your format constraints NSLayoutConstraint.activate
  • Use loadView as an alternative of viewDidLoad for creating views with constraints
  • Deal with reminiscence administration by utilizing weak properties
  • Set each different property like background colour, and so on. in viewDidLoad

Sufficient principle, here’s a brief instance:

class ViewController: UIViewController {

    weak var testView: UIView!

    override func loadView() {
        tremendous.loadView()

        let testView = UIView(body: .zero)
        testView.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(testView)
        NSLayoutConstraint.activate([
            testView.widthAnchor.constraint(equalToConstant: 64),
            testView.widthAnchor.constraint(equalTo: testView.heightAnchor),
            testView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
            testView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),
        ])
        self.testView = testView
    }

    override func viewDidLoad() {
        tremendous.viewDidLoad()

        self.testView.backgroundColor = .pink
    }
}

Fairly easy, huh? Only a few traces of code and you’ve got a hard and fast dimension heart aligned view with a devoted class property reference. In the event you create the very same by way of interface builder, the system will “make” you the loadView methodology at no cost, however you may need to setup an IBOutlet reference to the view.

The everlasting dilemma: code vs Interface Builder.

It actually would not issues, be at liberty to selected your path. Typically I really like taking part in round with IB, however in a lot of the instances I favor the programmatic approach of doing issues. 😛

Frequent UIKit auto format constraint use instances

So I promised that I will present you tips on how to make constraints programmatically, proper? Let’s do this now. To start with, I exploit nothing however format anchors. You may waste your time with the visible format language, however that is undoubtedly a lifeless finish. So mark my phrases: use solely anchors or stack views, however nothing else! 😇

Listed here are the most typical patterns that I exploit to create good layouts. 😉

Set fastened with or peak

First one is the simplest one: set a view’s peak or a width to a hard and fast level.

testView.widthAnchor.constraint(equalToConstant: 320),
testView.heightAnchor.constraint(equalToConstant: 240),

Set facet ratio

Settings a view’s facet ratio is simply constrainting the width to the peak or vica versa, you’ll be able to merely outline the speed by the multiplier.

testView.widthAnchor.constraint(equalToConstant: 64),
testView.widthAnchor.constraint(equalTo: testView.heightAnchor, multiplier: 16/9),

Heart horizontally & vertically

Centering views inside one other one is a trivial activity, there are particular anchors for that.

testView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
testView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),

Stretch or fill inside view with padding

The one difficult half right here is that trailing and backside constraints behave a bit of bit completely different, than prime & main if it involves the constants. Often you need to work with unfavorable values, however after a couple of tries you may perceive the logic right here. 😅

testView.topAnchor.constraint(equalTo: self.view.topAnchor, fixed: 32),
testView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, fixed: 32),
testView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, fixed: -32),
testView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, fixed: -32),

Proportional width or peak

In the event you do not wish to work with fixed values, you should utilize the multiplier.

testView.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 1/3),
testView.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 2/3),

Utilizing secure space format guides

With the newest iPhone you may want some guides in an effort to hold you secure from the notch. That is the explanation why views have the safeAreaLayoutGuide property. You will get all the standard anchors after calling out to the secure space information. 💪

testView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor),
testView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor),
testView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor),
testView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor),

Animating format constraints

Animation with constraints is simple, you should not consider what others may say. I made some guidelines and an instance that’ll assist you understanding the essential rules of animating fixed values of a constraint, plus toggling varied constraints. 👍

Guidelines:

  • Use normal UIView animation with layoutIfNeeded
  • All the time deactivate constraints first
  • Maintain to your deactivated constraints strongly
  • Have enjoyable! 😛

Constraint animation instance:

class ViewController: UIViewController {

    weak var testView: UIView!
    weak var topConstraint: NSLayoutConstraint!
    var bottomConstraint: NSLayoutConstraint!
    var heightConstraint: NSLayoutConstraint!

    override func loadView() {
        tremendous.loadView()

        let testView = UIView(body: .zero)
        testView.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(testView)

        let topConstraint = testView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor)
        let bottomConstraint = testView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor)

        NSLayoutConstraint.activate([
            topConstraint,
            testView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor),
            testView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor),
            bottomConstraint,
        ])

        let heightConstraint = testView.heightAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.heightAnchor, multiplier: 0.5)

        self.testView = testView
        self.topConstraint = topConstraint
        self.bottomConstraint = bottomConstraint
        self.heightConstraint = heightConstraint
    }

    override func viewDidLoad() {
        tremendous.viewDidLoad()

        self.testView.backgroundColor = .pink

        let faucet = UITapGestureRecognizer(goal: self, motion: #selector(self.tapped))
        self.view.addGestureRecognizer(faucet)
    }

    @objc func tapped() {
        if self.topConstraint.fixed != 0 {
            self.topConstraint.fixed = 0
        }
        else {
            self.topConstraint.fixed = 64
        }

        if self.bottomConstraint.isActive {
            NSLayoutConstraint.deactivate([self.bottomConstraint])
            NSLayoutConstraint.activate([self.heightConstraint])

        }
        else {
            NSLayoutConstraint.deactivate([self.heightConstraint])
            NSLayoutConstraint.activate([self.bottomConstraint])
        }

        UIView.animate(withDuration: 0.25) {
            self.view.layoutIfNeeded()
        }
    }
}

It is not that unhealthy, subsequent: adaptivity and supporting a number of gadget display sizes. 🤔

Easy methods to create adaptive layouts for iOS? Even Apple is combating adaptive layouts within the built-in iOS purposes. In the event you take a look at apps which might be made with assortment views – like photographs – layouts are fairly okay on each gadget. Nevertheless there are a couple of different ones, that – for my part – are horrible experiences on a much bigger display. 🤐

Rotation help

Your first step to adaptive format is supporting a number of gadget orientations. You possibly can examine my earlier article about iOS auto format there are many nice stuff inside that article about rotation help, working with layers inside auto format land, and so on. 🌈

Trait collections

Second step is to adapt trait collections. UITraitCollection is there so that you can group all of the environmental particular traits akin to dimension courses, show scale, person interface idiom and plenty of extra. A lot of the instances you’ll have to examine the vertical & horizontal dimension courses. There’s a reference of gadget dimension courses and all of the attainable variations made by Apple, see the exterior sources part beneath. 😉

This little Swift code instance beneath is demonstrating tips on how to examine dimension courses for setting completely different layouts for compact and common screens.

class ViewController: UIViewController {

    weak var testView: UIView!

    var regularConstraints: [NSLayoutConstraint] = []
    var compactConstraints: [NSLayoutConstraint] = []

    override func loadView() {
        tremendous.loadView()

        let testView = UIView(body: .zero)
        testView.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(testView)

        self.regularConstraints = [
            testView.widthAnchor.constraint(equalToConstant: 64),
            testView.widthAnchor.constraint(equalTo: testView.heightAnchor),
            testView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
            testView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),
        ]

        self.compactConstraints = [
            testView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor),
            testView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor),
            testView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor),
            testView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor),
        ]

        self.activateCurrentConstraints()

        self.testView = testView
    }

    personal func activateCurrentConstraints() {
        NSLayoutConstraint.deactivate(self.compactConstraints + self.regularConstraints)

        if self.traitCollection.verticalSizeClass == .common {
            NSLayoutConstraint.activate(self.regularConstraints)
        }
        else {
            NSLayoutConstraint.activate(self.compactConstraints)
        }
    }

    override func viewDidLoad() {
        tremendous.viewDidLoad()

        self.testView.backgroundColor = .pink
    }

    

    override var shouldAutorotate: Bool {
        return true
    }

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .allButUpsideDown
    }

    override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
        return .portrait
    }

    

    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        tremendous.traitCollectionDidChange(previousTraitCollection)

        self.activateCurrentConstraints()
    }
}

System detection

You may also examine the person interface idiom by way of the UIDevice class (aka. is that this freakin’ gadget an iPhone or an iPad?) to set for instance font sizes based mostly on it. 📱

UIDevice.present.userInterfaceIdiom == .pad

Display dimension

An alternative choice to determine your atmosphere is checking the dimension of the display. You possibly can examine the native pixel rely or a relative dimension based mostly in factors.


UIScreen.most important.nativeBounds   
UIScreen.most important.bounds         

Often I am attempting to maintain myself to those guidelines. I do not actually keep in mind a state of affairs the place I wanted greater than all of the issues I’ve listed above, however in case you have a selected case or questions, please do not hesitate to contact me. 😉

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments