Vistas Programaticas
Todos los elementos del utilizados en el interface builder, tanto en Storyboards y Xibs corresponden a objetos del UIKit, por lo tanto pueden ser instanciables y extensibles desde codigo.
Herencia
Se puede crear una clase heredada de clases de CocoaTouch, con la cual se pueden sobre escribir los inicializadores
init(frame: CGRect)
crea a partir de un CGRectinit?(coder aDecoder: NSCoder)
crea apartir de un objecto NSCoder, generalmente este metodo es llamado cuando el Storyboard inicializa el objeto. Ademas de ello se puede tener un inicializador de conveniencia con unCGRect.zero
class MyView: UIView {
convenience init() {
self.init(frame: .zero)
}
override init(frame: CGRect) {
super.init(frame: frame)
setupAutoLayout()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupAutoLayout()
}
func setupAutoLayout(){
// here goes my code
}
}
Setup UIView objects
Dado que todos los elementos del UIView heredan del mismo cuentan con attributos que nos permiten customizar de la misma manera que lo hariamos en el interface builder.
let iv = UIImageView(frame: .zero)
iv.image = UIImage(named: "tacocat")!
iv.contentMode = .scaleAspectFit
iv.backgroundColor = .purple
Constraint
Para crear constraints es necesario establecer translatesAutoresizingMaskIntoConstraints
en false
en cada uno de los objectos a agregar a la vista, ya que sin ello los constraint no aplicaran a ese objeto.
iv.translatesAutoresizingMaskIntoConstraints = false
Una vez condigurado nuesto objecto, devemos agregarlo como Subview
view.addSubview(imageView)
Esto seria el similar al agregar un objecto en el interface builder sin establecer un constraint. Para crear un constraint por medio de codigo es necesario agregar el siguiente codigo
let constraint = imageView.topAnchor.constraint(equalTo: self.topAnchor)
Sin embargo nuestro constraint no esta listo, ya que necestamos explicitamente decir que sea activado
constraint.activate = true
En ejemplos en linea es mas comun encontrarlo asi
imageView.topAnchor.constraint(equalTo: self.topAnchor).activate = true
Sin embargo al realizar constraints de esta manera se convierte repetitivo, para una estraegia DRY
se puede utilizar NSLayoutConstraint
quien a travez del metodo activate, activa una lista de constraints.
NSLayoutConstraint.activate([
imageView.topAnchor.constraint(equalTo: self.topAnchor),
imageView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
imageView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
imageView.bottomAnchor.constraint(equalTo: self.bottomAnchor)
])
Por lo tanto nuesto archivo final quedaria de la siguiente forma
// CatView.swift
import UIKit
class CatView: UIView {
private let imageView: UIImageView = {
let iv = UIImageView(frame: .zero)
iv.image = UIImage(named: "tacocat")!
iv.contentMode = .scaleAspectFit
iv.translatesAutoresizingMaskIntoConstraints = false
return iv
}()
convenience init() {
self.init(frame: .zero)
}
override init(frame: CGRect) {
super.init(frame: frame)
setupAutoLayout()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupAutoLayout()
}
func setupAutoLayout() {
backgroundColor = .red
addSubview(imageView)
NSLayoutConstraint.activate([
imageView.topAnchor.constraint(equalTo: self.topAnchor),
imageView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
imageView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
imageView.bottomAnchor.constraint(equalTo: self.bottomAnchor)
])
}
}
@IBInspectable / @IBDesignable
Desafortunadamente los elementos generados programaticamente tienden a ser tediosos
ya que para visualizarlos es necesario compilar y accesar a la vista correspondiente en el simulador.
Para eviar ello podemos hacer uso de @IBDesignable
quien nos permite visualizar en el Storyboard
@IBDesignable
class CatView: UIView {
...
}
Una vez declarado un objeto como IBDesignable
se puede asignar a un view en el interface
builder, y al hacer esto automaticamente compila y renderiza el objeto .
Desafortunadamente esto requiere una compilacion en cada cambio sobre el archivo para ser
visualizado y esto puede hacer muy lenta la renderizacion.
De igual manera se pueden acceder a attributos de la clase en el interface builder por medio
de @IBInspectable
@IBDesignable
class CatView: UIView {
@IBInspectable var name: String?
...
}