started getting ios swift cocoa-touch uiview instantiation
Proyecto de ejemplo UIView (con ejemplo de SubView)

ios - getting - ¿Cómo escribo un init personalizado para una subclase de UIView en Swift?



load xib swift 4 (5)

Supongamos que quiero UIView una subclase UIView con String y un Int .

¿Cómo haría esto en Swift si solo estoy subclasificando UIView ? Si acabo de hacer una función personalizada de init() pero los parámetros son un String y un Int, me dice que "super.init () no se llama antes de regresar desde el inicializador".

Y si llamo a super.init() , me dicen que debo usar un inicializador designado. ¿Qué debería estar usando allí? La versión de marco? La versión del codificador? ¿Ambos? ¿Por qué?


Así es como hago una subvista en iOS en Swift:

class CustomSubview : UIView { init() { super.init(frame: UIScreen.mainScreen().bounds); let windowHeight : CGFloat = 150; let windowWidth : CGFloat = 360; self.backgroundColor = UIColor.whiteColor(); self.frame = CGRectMake(0, 0, windowWidth, windowHeight); self.center = CGPoint(x: UIScreen.mainScreen().bounds.width/2, y: 375); //for debug validation self.backgroundColor = UIColor.grayColor(); print("My Custom Init"); return; } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented"); } }


Así es como lo hago en iOS 9 en Swift:

import UIKit class CustomView : UIView { init() { super.init(frame: UIScreen.mainScreen().bounds); //for debug validation self.backgroundColor = UIColor.blueColor(); print("My Custom Init"); return; } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented"); } }

Aquí hay un proyecto completo con un ejemplo:


Creo un init común para el designado y requerido. Para su conveniencia, delego a init(frame:) con frame of zero.

Tener un marco cero no es un problema porque, por lo general, la vista se encuentra dentro de la vista de ViewController. La supervista llama a layoutSubviews() o updateConstraints() que el sistema llama de forma recursiva a lo largo de la jerarquía de vistas.

Si su vista personalizada tiene subvistas, puede establecer los marcos de las updateContstraints() en updateContstraints() o en layoutSubviews() . updateContstraints() se llama primero, luego layoutSubviews() . En updateConstraints() asegúrese de llamar a super último . En layoutSubviews() , llame a super primero .

Esto es lo que hago:

class MyView: UIView { convenience init(args: Whatever) { self.init(frame: CGRect.zero) //assign custom vars } override init(frame: CGRect) { super.init(frame: frame) commonInit() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) commonInit() } private func commonInit() { //custom initialization } override func updateConstraints() { //set subview constraints here super.updateConstraints() } override func layoutSubviews() { super.layoutSubviews() //manually set subview frames here } }


He intentado estas publicaciones aceptadas de personalizar init y todavía encuentro que son complicadas de implementar y llamar desde otras partes de tu código. Por lo tanto, solo para algunos principiantes como yo que prefieren usar el guión gráfico para una vista personalizada:

Puede personalizar estas propiedades agregando el atributo de @IBInspectable al comienzo de sus declaraciones y cambiar sus valores en la parte superior del inspector de atributos de XCode. Por último, recuerde agregar el observador de propiedades para llamar comportamientos personalizados a estas propiedades inspeccionables. El observador recibe una llamada para cargar XIB en lugar de en la inicialización.


La versión init(frame:) es el inicializador predeterminado. Debe llamarlo solo luego de inicializar sus variables de instancia. Si esta vista se está reconstituyendo desde un Nib, entonces no se llamará a su inicializador personalizado, y en su lugar se llamará a la versión de init?(coder:) . Como Swift ahora requiere una implementación del init?(coder:) requerido, he actualizado el ejemplo a continuación y cambié las declaraciones de variables de let a var y opcional. En este caso, los inicializaría en awakeFromNib() o en algún momento posterior.

class TestView : UIView { var s: String? var i: Int? init(s: String, i: Int) { self.s = s self.i = i super.init(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } }