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