Thursday, March 23, 2023
HomeiOS DevelopmentMastering iOS auto structure anchors programmatically from Swift

Mastering iOS auto structure anchors programmatically from Swift


In search of greatest practices of utilizing structure anchors? Let’s learn to use the iOS autolayout system within the correct manner utilizing Swift.

iOS

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 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 calcuations 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
  • Deal with reminiscence administration through the use of weak properties
  • Set each different property like background coloration, and many others. 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 = .pink
    }
}

Fairly easy, huh? Just some strains of code and you’ve got a hard and fast dimension heart aligned view with a devoted class property reference. For those who create the very same by way of interface builder, the system will “make” you the loadView technique at no cost, however you will 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 like enjoying round with IB, however in a lot of the instances I want the programmatic manner of doing issues. 😛


Frequent UIKit auto structure constraint use instances

So I promised that I will present you make constraints programmatically, proper? Let’s try this now. To start with, I exploit nothing however structure anchors. You possibly 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 commonest patterns that I exploit to create good layouts. 😉

Set mounted with or top

First one is the simplest 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 side ratio

Settings a view’s side ratio is simply constrainting the width to the peak or vica versa, you may 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 activity, there are particular anchors for that.

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

Stretch | fill inside view with padding

The one tough half right here is that trailing and backside constraints behave a bit of bit totally different, than high & main if it involves the constants. Often you must work with detrimental values, however after a couple of tries you will 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

For those who 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 protected space structure guides

With the newest iPhone you will want some guides to be able to maintain you protected from the notch. That is the rationale why views have the safeAreaLayoutGuide property. You will get all the standard anchors after calling out to the protected 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 imagine what others may say. I made some guidelines and an instance that’ll aid you understanding the fundamental rules of animating fixed values of a constraint, plus toggling numerous constraints. 👍

Guidelines:

  • Use customary UIView animation with layoutIfNeeded
  • At all times 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 dangerous, subsequent: adaptivity and supporting a number of gadget display screen sizes. 🤔


Methods to create adaptive layouts for iOS?

Even Apple is fighting adaptive layouts within the built-in iOS purposes. For those who have a look at apps which are made with assortment views – like photographs – layouts are fairly okay on each gadget. Nonetheless there are a couple of different ones, that – for my part – are horrible experiences on an even bigger display screen. #justusecollectionviewforeverything. 🤐

Rotation assist

Your first step to adaptive structure is supporting a number of gadget orientations. You may verify my earlier article about iOS auto structure there are many nice stuff inside that article about rotation assist, working with layers inside auto structure land, and many others. 🌈

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 dimension courses, show scale, consumer interface idom and lots of extra. Many of the occasions you’ll have to verify the vertical & horizontal dimension courses. There’s a reference of gadget dimension courses and all of the potential variations made by Apple, see the exterior sources part under. 😉

This little Swift code instance under is demonstrating verify dimension 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
    }

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

Gadget detection

You may also verify the consumer interface idom 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

Another choice to determine your atmosphere is checking the dimension of the display screen. You may verify the native pixel rely or a relative dimension based mostly in factors.


UIScreen.major.nativeBounds   
UIScreen.major.bounds         

Often I am making an attempt 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 when 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