Fading Coder

One Final Commit for the Last Sprint

Home > Tools > Content

Using Swift Auto Layout for Dynamic and Fixed UI Elements

Tools 1

Position two UILabel instances in code where the top label miantains a fixed size and the bottom label wraps text based on its content using Auto Layout.

import UIKit

class LayoutController: UIViewController {

    let headerLbl: UILabel = {
        let lbl = UILabel()
        lbl.translatesAutoresizingMaskIntoConstraints = false
        lbl.text = "Header"
        lbl.textAlignment = .center
        lbl.backgroundColor = .systemGray5
        return lbl
    }()

    let bodyLbl: UILabel = {
        let lbl = UILabel()
        lbl.translatesAutoresizingMaskIntoConstraints = false
        lbl.text = "Resizable content that wraps across multiple lines depending on length. Resizable content that wraps across multiple lines depending on length."
        lbl.numberOfLines = 0
        lbl.textAlignment = .center
        lbl.backgroundColor = .systemYellow
        return lbl
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        view.addSubview(headerLbl)
        view.addSubview(bodyLbl)
        applyVerticalConstraints()
    }

    func applyVerticalConstraints() {
        NSLayoutConstraint.activate([
            headerLbl.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
            headerLbl.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
            headerLbl.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
            headerLbl.heightAnchor.constraint(equalToConstant: 50)
        ])

        NSLayoutConstraint.activate([
            bodyLbl.topAnchor.constraint(equalTo: headerLbl.bottomAnchor, constant: 20),
            bodyLbl.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
            bodyLbl.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
            bodyLbl.bottomAnchor.constraint(lessThanOrEqualTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20)
        ])
    }
}

For a side-by-side arrangement, anchor labels horizontally with one having a constant width:

let sideALbl: UILabel = {
    let lbl = UILabel()
    lbl.translatesAutoresizingMaskIntoConstraints = false
    lbl.text = "Left"
    lbl.textAlignment = .center
    lbl.backgroundColor = .systemGray4
    return lbl
}()

let sideBLbl: UILabel = {
    let lbl = UILabel()
    lbl.translatesAutoresizingMaskIntoConstraints = false
    lbl.text = "Right area can expand vertically if needed. Right area can expand vertically if needed."
    lbl.numberOfLines = 0
    lbl.textAlignment = .center
    lbl.backgroundColor = .systemOrange
    return lbl
}()

override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = .white
    view.addSubview(sideALbl)
    view.addSubview(sideBLbl)
    applyHorizontalConstraints()
}

func applyHorizontalConstraints() {
    NSLayoutConstraint.activate([
        sideALbl.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
        sideALbl.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
        sideALbl.widthAnchor.constraint(equalToConstant: 100),
        sideALbl.heightAnchor.constraint(equalToConstant: 50)
    ])

    NSLayoutConstraint.activate([
        sideBLbl.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
        sideBLbl.leadingAnchor.constraint(equalTo: sideALbl.trailingAnchor, constant: 20),
        sideBLbl.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
        sideBLbl.bottomAnchor.constraint(greaterThanOrEqualTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20)
    ])
}

To allocate proportional widths between labels, use a multiplier relative to the parent view:

func applyProportionalWidths() {
    NSLayoutConstraint.activate([
        sideALbl.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
        sideALbl.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
        sideALbl.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.3),
        sideALbl.heightAnchor.constraint(equalToConstant: 50)
    ])

    NSLayoutConstraint.activate([
        sideBLbl.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
        sideBLbl.leadingAnchor.constraint(equalTo: sideALbl.trailingAnchor, constant: 20),
        sideBLbl.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
        sideBLbl.bottomAnchor.constraint(greaterThanOrEqualTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20)
    ])
}

Related Articles

Efficient Usage of HTTP Client in IntelliJ IDEA

IntelliJ IDEA incorporates a versatile HTTP client tool, enabling developres to interact with RESTful services and APIs effectively with in the editor. This functionality streamlines workflows, replac...

Installing CocoaPods on macOS Catalina (10.15) Using a User-Managed Ruby

System Ruby on macOS 10.15 frequently fails to build native gems required by CocoaPods (for example, ffi), leading to errors like: ERROR: Failed to build gem native extension checking for ffi.h... no...

Resolve PhpStorm "Interpreter is not specified or invalid" on WAMP (Windows)

Symptom PhpStorm displays: "Interpreter is not specified or invalid. Press ‘Fix’ to edit your project configuration." This occurs when the IDE cannot locate a valid PHP CLI executable or when the debu...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.