View Component

Remember the view code? We will talk about one of the benefits of creating applications with view code.

Se você não está familiarizado com o view code, recomendo ler esse POST.

Let's go to practice:

Let's create the UI for a project that will simulate the auction system in which the auctioneer and the people who will bid will have:

To start the view code, we have to make some preparations POST.

ViewControlller.swift

class ViewController: UIViewController {
    let uiAuction = UIAuction()

    override func loadView() {

        self.view = uiAuction
    }

    override func viewDidLoad() {
        super.viewDidLoad()

    }
}

Let's instantiate UIAuction because there the screen is the screen UI.

UIAuction.swift

This class will be called UIAuction, which has the UIView superclass.

import UIKit

class UIAuction: UIView {

     override init(frame: CGRect) {
         super.init(frame: frame)
     }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
 }

There will be two main attributes:

  • Auctioneer
  • People who will bid.

Let's componentize the auctioneer:

Auctioneer.swift

import UIKit

class Auctioneer: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)

    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

It will have the attributes:

  • Photo (UIImageView);
  • Final bid amount (UILabel);
  • Timer to finalize the auction (UILabel).

    //Attributes

    let imPerson: UIImageView = {
        let iv = UIImageView()
        iv.image = UIImage.init(systemName: "person")
        iv.contentMode = .scaleAspectFit
        iv.translatesAutoresizingMaskIntoConstraints = false

        return iv
    }()


    let lbValue: UILabel = {
        let lb = UILabel()
        lb.backgroundColor = .gray
        lb.font = .systemFont(ofSize: 25, weight: .bold)
        lb.textAlignment = .center
        lb.text = "Value"
        lb.translatesAutoresizingMaskIntoConstraints = false

        return lb
    }()

    let lbTime: UILabel = {
        let lb = UILabel()
        lb.backgroundColor = .gray
        lb.font = .systemFont(ofSize: 25, weight: .bold)
        lb.textAlignment = .center
        lb.text = "Time"
        lb.translatesAutoresizingMaskIntoConstraints = false

        return lb
    }()

To facilitate Auto Layout, we will use the UIStackView.


let container: UIStackView = {
    let stack = UIStackView(frame: .zero)
    stack.axis = .vertical
    stack.distribution = .fillEqually
    stack.spacing = 8

    stack.translatesAutoresizingMaskIntoConstraints = false

    return stack
}()

We will use the initializer, which will call two functions: One to add the attributes in UIStackView and the other to do Auto Layout. We also need to assign from the self.translatesAutoresizingMaskIntoConstraints = false view, for the automatic layout in UIAuction:

  override init(frame: CGRect) {
        super.init(frame: frame)

        self.translatesAutoresizingMaskIntoConstraints = false

        addAttributes()
        addConstraints()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func addAttributes(){
        self.container.addArrangedSubview(imPerson)
        self.container.addArrangedSubview(lbTime)
        self.container.addArrangedSubview(lbValue)

        self.addSubview(container)
    }

    func addConstraints(){

        NSLayoutConstraint.activate([

            self.container.bottomAnchor.constraint(equalTo: self.bottomAnchor),
            self.container.topAnchor.constraint(equalTo: self.topAnchor),
            self.container.leadingAnchor.constraint(equalTo: self.leadingAnchor),
            self.container.trailingAnchor.constraint(equalTo: self.trailingAnchor),

        ])
    }

We created our component let's go back to UIAuction to show it in the view:

Auctioneer.swift

class Auctioneer: UIView {

    let auctioneer = Auctioneer()

    override init(frame: CGRect) {
        super.init(frame: frame)

    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

let's add the component on the screen and do Auto Layout in the addAuctioneer() function

    override init(frame: CGRect) {
        super.init(frame: frame)

        self.backgroundColor = .systemBackground

        self.addIUAuctioneer()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func addIUAuctioneer(){
        self.addSubview(auctioneer)

        NSLayoutConstraint.activate([

            self.auctioneer.topAnchor.constraint(equalTo: self.layoutMarginsGuide.topAnchor),
            self.auctioneer.centerXAnchor.constraint(equalTo: self.centerXAnchor),
            self.auctioneer.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.3),

        ])
    }

Let's run the app

Simulator Screen Shot - iPhone 12 Pro Max - 2021-03-12 at 15 41 53

Let's do the component of the people who are going to bid

Person.swift

Let's create the attributes:

  • UIImageView - photo;
  • UILabel - show the minimum amount that the bid can accept;
  • UITextField - enter the bid amount;
  • UIButton - send to the auctioneer.
import UIKit

class Person: UIView {

    //Atributtes
    let imPerson: UIImageView = {
        let iv = UIImageView()

        iv.image = UIImage.init(systemName: "person")
        iv.contentMode = .scaleAspectFit
        iv.translatesAutoresizingMaskIntoConstraints = false

        return iv
    }()

    let tfValueFirstPerson: UITextField = {
        let tf = UITextField()
        tf.placeholder = "Enter value"
        tf.font = UIFont.systemFont(ofSize: 25)
        tf.borderStyle = UITextField.BorderStyle.roundedRect
        tf.keyboardType = UIKeyboardType.numberPad
        tf.returnKeyType = UIReturnKeyType.done
        tf.clearButtonMode = UITextField.ViewMode.whileEditing

        tf.addTarget(self, action: #selector(editValueFirstPerson), for: .editingChanged)
        tf.translatesAutoresizingMaskIntoConstraints = false

        return tf
    }()

    var btnSendValue: UIButton = {
        let btn = UIButton()
        btn.setTitle("Send", for: .normal)
        btn.backgroundColor = .green
        btn.titleLabel?.font = .systemFont(ofSize: 25, weight: .medium)
        btn.translatesAutoresizingMaskIntoConstraints = false
        btn.addTarget(self, action: #selector(setValueFirstPerson), for: .touchUpInside)

        return btn
    }()

    let lbValue: UILabel = {
        let lb = UILabel()
        lb.backgroundColor = .gray
        lb.font = .systemFont(ofSize: 25, weight: .bold)
        lb.textAlignment = .center
        lb.text = "Value"
        lb.translatesAutoresizingMaskIntoConstraints = false

        return lb
    }()


}

Note: We still have to do the actions why it is giving an error.

We will use the stackview again.

let container: UIStackView = {
    let stack = UIStackView(frame: .zero)
    stack.axis = .vertical
    stack.distribution = .fillEqually
    stack.spacing = 8

    stack.translatesAutoresizingMaskIntoConstraints = false

    return stack
}()

The builder will call the addPerson() and addConstraints() function. The first to add the attributes in the UIStackView and the second to place the Auto Layout:

override init(frame: CGRect) {
    super.init(frame: frame)

    self.translatesAutoresizingMaskIntoConstraints = false

    addPerson()
    addConstraints()
}

required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

func addPerson(){

    self.container.addArrangedSubview(imPerson)
    self.container.addArrangedSubview(tfValueFirstPerson)
    self.container.addArrangedSubview(btnSendValue)
    self.container.addArrangedSubview(lbValue)

    self.addSubview(container)
}

func addConstraints(){
    NSLayoutConstraint.activate([

        self.container.bottomAnchor.constraint(equalTo: self.bottomAnchor),
        self.container.topAnchor.constraint(equalTo: self.topAnchor),
        self.container.leadingAnchor.constraint(equalTo: self.leadingAnchor),
        self.container.trailingAnchor.constraint(equalTo: self.trailingAnchor),

    ])
}

The actions will have a problem because we will make three people and we will have to identify them.

let's create the actions:

@objc func editValueFirstPerson(_ textField: UITextField){
    guard let name = textField.accessibilityIdentifier else { return }

    print(name)
}

@objc func setValueFirstPerson(_ button: UIButton){
    guard let name = button.accessibilityIdentifier else { return }
    print(name)


}

Note: As the focus is on the UI. So we will leave the actions here otherwise we could do it another way.

UIAuction.swift

Let's make three people:

import UIKit

class UIAuction: UIView {

    let personOne: Person = {
        let person = Person()
        person.btnSendValue.accessibilityIdentifier = "button1"
        person.tfValueFirstPerson.accessibilityIdentifier = "tfValueFirstPerson1"

        return person
    }()

    let personTwo: Person = {
        let person = Person()
        person.btnSendValue.accessibilityIdentifier = "button2"
        person.tfValueFirstPerson.accessibilityIdentifier = "tfValueFirstPerson2"

        return person
    }()

    let personThree: Person = {
        let person = Person()
        person.btnSendValue.accessibilityIdentifier = "button3"
        person.tfValueFirstPerson.accessibilityIdentifier = "tfValueFirstPerson3"

        return person
    }()

    let auctioneer = Auctioneer()

Note that we identified the UIButton and the UITextField, to find out who clicked the button or wrote in the UITextField.

As there are three people, we will use the UIStackView in the components:

var container: UIStackView = {
    let container = UIStackView(frame: .zero)
    container.axis = .horizontal
    container.distribution = .fillEqually
    container.spacing = 5

    container.translatesAutoresizingMaskIntoConstraints = false

    return container
}()

Let's add the elements in the UIStackView and do the Auto Layout of the UIStackView.


 override init(frame: CGRect) {
        super.init(frame: frame)

        self.backgroundColor = .systemBackground

        self.addUIAuctioneer()
        self.addUIPerson()

    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func addUIPerson(){

        container.addArrangedSubview(personOne)
        container.addArrangedSubview(personTwo)
        container.addArrangedSubview(personThree)

        self.addSubview(container)

        NSLayoutConstraint.activate([

            self.container.centerYAnchor.constraint(equalTo:self.layoutMarginsGuide.centerYAnchor),
            self.container.centerXAnchor.constraint(equalTo:self.layoutMarginsGuide.centerXAnchor),

            self.container.leadingAnchor.constraint(equalTo: self.leadingAnchor),
            self.container.trailingAnchor.constraint(equalTo: self.trailingAnchor),
            self.container.heightAnchor.constraint(equalToConstant: 200)
        ])
    }

Result

Simulator Screen Shot - iPhone 12 Pro Max - 2021-03-13 at 11 58 42

GitHub