Customized views, enter varieties and errors


How NOT to construct varieties for iOS apps?

Let’s begin with an trustworthy assertion: I tousled with this tutorial (quite a bit):

Constructing enter varieties for iOS apps

The factor is that this kind constructing methodology solely works if the cells are at all times seen on display screen, which is kind of a uncommon case. I found this problem whereas I used to be engaged on my present venture and a few fields had been always disappearing and shifting the cursor to the following enter subject stopped working when the cell was out of body.

Reusability & reminiscence effectivity isn’t at all times what you need.

Looks like UICollectionView isn’t one of the best resolution for making enter varieties, as a result of the fixed cell reusability will mess up a number of the anticipated habits. It is nonetheless good for lists with “a thousand components”, however for an enter type I’d not suggest this system anymore. Yep, my mistake, sorry about it… 😬

Studying by making errors

Lengthy story quick, I made a mistake and doubtless you will additionally make quite a bit throughout your developer profession. Does this make you a foul programmer? Under no circumstances. We’re human, we’re always making smaller or larger errors, however…

(Stay and) flip it into power

Your errors will at all times stick with you, however you’ll be able to be taught from them quite a bit. The issue solely begins in case you maintain doing the identical errors repeatedly, or you do not even notice that you just’re doing one thing mistaken. It is actually exhausting to take one step again and see the issue from an even bigger perspective. Typically you merely want another person to level out the difficulty for you, however damaging suggestions will also be painful.

Anyway, I do not wish to be an excessive amount of philosophical, this can be a Swift developer weblog ffs.

Just a few issues that I discovered:

  • my concepts are usually not at all times working, so do not belief me 100% (haha) 🤣
  • it is at all times higher to code/work in pair with another person
  • generally the “padawan” will train the “grasp” 😉
  • an expert qa group can prevent a number of time
  • VIPER is my architectural “silver bullet”, not assortment views
  • UICollectionView primarily based type constructing isn’t working…
  • …however the assortment view framework nonetheless rocks for complicated interfaces
  • have some devoted time for code cosmetics & refactor
  • use view subclasses programmatically (or SwiftUI sooner or later)

So the final level is probably the most fascinating one, let me clarify why.

Customized view subclasses from code solely

Making a UIView subclass programmatically is a comparatively straightforward job. You’ll be able to load a nib file or you are able to do it straight from code. Just a few weeks in the past I’ve discovered a brand new trick, that was bugging me on a regular basis I made a brand new subclass in Swift:

Why the hell do I’ve to implement init(coder:) if I am not utilizing IB in any respect?

Additionally what the heck is occurring with init(body:), I do not wish to take care of these two init strategies anymore, since I am utilizing auto structure and I am utterly attempting to disregard interface builder with the tousled storyboards and nibs as properly.

class View: UIView {

    @out there(*, unavailable)
    override init(body: CGRect) {
        tremendous.init(body: body)

        self.initialize()
    }

    @out there(*, unavailable)
    required init?(coder aDecoder: NSCoder) {
        tremendous.init(coder: aDecoder)

        self.initialize()
    }

    init() {
        tremendous.init(body: .zero)

        self.initialize()
    }

    func initialize() {
        self.translatesAutoresizingMaskIntoConstraints = false
    }
}

The answer: mark these silly init capabilities as unavailable, so no-one can use them anymore. The one supply of reality will likely be your personal init technique, which is kind of a reduction in case you had been so irritated concerning the tousled initialization course of like I used to be. 😤

Now you’ve gotten your personal base class that you should utilize as a mother or father to your future views. In fact you will have to do the identical factor for nearly each UI aspect, like labels, buttons, textual content fields, and so on. That is a number of work, however on a long run it’s very value it.

import UIKit

class TitleLabel: Label {

    override func initialize() {
        tremendous.initialize()

        self.textAlignment = .middle
        self.font = UIFont.preferredFont(forTextStyle: .largeTitle)
        self.textColor = .systemBlue
    }

    func constraints(in view: UIView, padding: CGFloat = 8) -> [NSLayoutConstraint] {
        [
            self.topAnchor.constraint(equalTo: view.topAnchor, constant: padding),
            self.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: padding),
            self.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -1 * padding),
        ]
    }
}

An excellent follow might be to have subclass for each customized consumer interface element, like the first button, secondary button, title label, header label, and so on. This manner you do not have to configure your views within the view controller, plus you’ll be able to put your continuously used constraints into the subclass utilizing some helper strategies.

Additionally you’ll be able to have some good extensions, these may also help you with view configurations. You understand, similar to modifiers in SwiftUI. You’ll be able to even recreate the very same syntax. The underlying habits will not be the identical, however that is one other story. 📚

What concerning the type new builder in iOS?

Oh, yeah nearly forgot. I’ve a model new, however nonetheless very comparable resolution. I am utilizing view subclasses as a substitute of assortment view parts, plus the gathering view have been changed with a UIScrollView + UIStackView mixture. 🐐

class ViewController: UIViewController {

    weak var scrollView: ScrollView!
    weak var stackView: VerticalStackView!

    override func loadView() {
        tremendous.loadView()

        let scrollView = ScrollView()
        self.view.addSubview(scrollView)
        self.scrollView = scrollView
        NSLayoutConstraint.activate([])

        let stackView = VerticalStackView()
        self.scrollView.addSubview(stackView)
        self.stackView = stackView
        NSLayoutConstraint.activate([])
    }

    override func viewDidLoad() {
        tremendous.viewDidLoad()

        self.title = "StackForm"
        self.navigationController?.navigationBar.prefersLargeTitles = true

        let electronic mail = EmailTextField(id: "email-input", placeholder: "Electronic mail")
        self.stackView.addArrangedSubview(electronic mail)

        let password = PasswordTextField(id: "password-input", placeholder: "Password")
        self.stackView.addArrangedSubview(password)

        let submit = SubmitButton(id: "submit-button", title: "Submit")
        .onTouch { [weak self] _ in self?.submit() }
        self.stackView.addArrangedSubview(submit)
    }

    func submit() {
        guard
            let electronic mail = (self.view.view(withId: "email-input") as? UITextField)?.textual content,
            let password = (self.view.view(withId: "password-input") as? UITextField)?.textual content
        else {
            return
        }
        print("Account: (electronic mail) - (password)")
    }
}

As you’ll be able to see I am nonetheless utilizing the identical view identification approach, plus I nonetheless favor to have the SwiftUI-like .onTouch motion handlers. You would possibly ask although:

Why do not you merely go along with SwiftUI?

Properly, the factor is that SwiftUI is iOS 13 solely, which is just round ~55% adoption these days, that is one of many important causes, but additionally SwiftUI is type of incomplete.

I am attempting to get as shut as I can to SwiftUI, so the transition will likely be much less ache within the ass when the time comes. SwiftUI will likely be wonderful, however nonetheless it is a big leap ahead. Typically I imagine that Apple is speeding issues simply due to advertising and marketing / developer wants (yeah, we’re very impatient animals). Perhaps a easy wrapper framework round UIKit / AppKit with out the entire declarative syntax would have been a greater thought as a primary step… who is aware of… CoreKit -> AppleKit? 🤔

Anyway, you’ll be able to obtain a working instance of my newest type constructing resolution in Swift 5 from GitHub. Simply search for the StackForm folder contained in the repository.

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles