Saturday, October 14, 2023
HomeiOS DevelopmentMastering iOS auto structure anchors programmatically from Swift

Mastering iOS auto structure anchors programmatically from Swift


Creating views and constraints programmatically

To begin with I would prefer to recap the UIViewController life cycle strategies, you’re may acquainted with a few of them. They’re being referred to as within the following order:

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

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

These are the fundamental guidelines of making view hierarchies utilizing auto structure:

  • 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 structure constraints NSLayoutConstraint.activate
  • Use loadView as a substitute of viewDidLoad for creating views with constraints
  • Handle reminiscence administration by utilizing weak properties
  • Set each different property like background shade, and so forth. in viewDidLoad

Sufficient concept, 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 = .crimson
    }
}

Fairly easy, huh? Only a few strains of code and you’ve got a hard and fast measurement 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 technique without spending a dime, however you may need to setup an IBOutlet reference to the view.

The everlasting dilemma: code vs Interface Builder.

It actually does not issues, be happy to selected your path. Generally I really like taking part in round with IB, however in a lot of the instances I want the programmatic method of doing issues. 😛

Frequent UIKit auto structure constraint use instances

So I promised that I am going to present you the right way to make constraints programmatically, proper? Let’s do this now. To begin with, I take advantage of nothing however structure anchors. You can 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 below are the most typical patterns that I take advantage of to create good layouts. 😉

Set fastened with or top

First one is the most straightforward one: set a view’s top 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 possibly can merely outline the speed by the multiplier.

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

Middle horizontally & vertically

Centering views inside one other one is a trivial job, 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 somewhat bit totally different, than high & main if it involves the constants. Normally you need to work with destructive values, however after a number 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 top

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 structure guides

With the newest iPhone you may want some guides with the intention to preserve you secure from the notch. That is the explanation why views have the safeAreaLayoutGuide property. You will get all the same old 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 structure constraints

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

Guidelines:

  • Use customary 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 = .crimson

        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 isn’t that dangerous, subsequent: adaptivity and supporting a number of system display sizes. 🤔

The right way to create adaptive layouts for iOS? Even Apple is fighting adaptive layouts within the built-in iOS purposes. In the event you take a look at apps which are made with assortment views – like images – layouts are fairly okay on each system. Nevertheless there are a number of different ones, that – for my part – are horrible experiences on a much bigger display. 🤐

Rotation help

Your first step to adaptive structure is supporting a number of system orientations. You’ll be able to test my earlier article about iOS auto structure there are many nice stuff inside that article about rotation help, working with layers inside auto structure land, and so forth. 🌈

Trait collections

Second step is to adapt trait collections. UITraitCollection is there so that you can group all of the environmental particular traits reminiscent of measurement courses, show scale, consumer interface idiom and lots of extra. Many of the instances you’ll have to test the vertical & horizontal measurement courses. There’s a reference of system measurement courses and all of the attainable variations made by Apple, see the exterior sources part under. 😉

This little Swift code instance under is demonstrating the right way to test measurement courses for setting totally 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
    }

    non-public 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 = .crimson
    }

    

    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()
    }
}

Machine detection

You too can test the consumer interface idiom by way of the UIDevice class (aka. is that this freakin’ system an iPhone or an iPad?) to set for instance font sizes based mostly on it. 📱

UIDevice.present.userInterfaceIdiom == .pad

Display screen measurement

Another choice to determine your setting is checking the measurement of the display. You’ll be able to test the native pixel depend or a relative measurement based mostly in factors.


UIScreen.major.nativeBounds   
UIScreen.major.bounds         

Normally I am attempting to maintain myself to those guidelines. I do not actually bear 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. 😉



Supply hyperlink

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments