Quiero crear UIView
una subclase y mostrar una vista de inicio de sesión. Creé esto en Objective-C, pero ahora quiero portarlo a Swift. No uso guiones gráficos, así que creo toda mi interfaz de usuario en código.
Pero el primer problema es que debo implementar initWithCoder
. Le di una implementación predeterminada ya que no se llamará. Ahora, cuando ejecuto el programa, se bloquea, porque también tengo que implementarlo initWithFrame
. Ahora tengo esto:
override init() {
super.init()
println("Default init")
}
override init(frame: CGRect) {
super.init(frame: frame)
println("Frame init")
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
println("Coder init")
}
Mi pregunta es dónde debería crear mi campo de texto, etc. y si nunca implemento el marco y el codificador, ¿cómo puedo "ocultar" esto?
CGRectZero
, creo que se recomienda usarCGRect.zeroRect
.Esto es más simple.
fuente
Ejemplo personalizado de subclase de UIView
Normalmente creo aplicaciones de iOS sin usar guiones gráficos o plumillas. Compartiré algunas técnicas que he aprendido para responder a sus preguntas.
Ocultar
init
métodos no deseadosMi primera sugerencia es declarar una base
UIView
para ocultar inicializadores no deseados. He discutido este enfoque en detalle en mi respuesta a "Cómo ocultar los inicializadores específicos del guión gráfico y la punta en las subclases de la interfaz de usuario" . Nota: Este enfoque asume que no usaráBaseView
o sus descendientes en guiones gráficos o plumillas, ya que provocará intencionalmente que la aplicación se bloquee.Su subclase personalizada de UIView debe heredar
BaseView
. Debe llamar a super.init () en su inicializador. No es necesario implementarloinit(coder:)
. Esto se demuestra en el ejemplo siguiente.Agregar un UITextField
Creo propiedades almacenadas para subvistas a las que se hace referencia fuera del
init
método. Normalmente lo haría para un UITextField. Yo prefiero subvistas crear una instancia dentro de la declaración de la propiedad subvista como esto:let textField = UITextField()
.UITextField no será visible a menos que lo agregue a la lista de subvista de la vista personalizada llamando a
addSubview(_:)
. Esto se demuestra en el ejemplo siguiente.Diseño programático sin diseño automático
UITextField no será visible a menos que establezca su tamaño y posición. A menudo hago el diseño en código (sin usar Auto Layout) dentro del método layoutSubviews .
layoutSubviews()
se llama inicialmente y siempre que ocurre un evento de cambio de tamaño. Esto permite ajustar el diseño según el tamaño de CustomView. Por ejemplo, si CustomView aparece en el ancho completo en varios tamaños de iPhones y iPads y se ajusta para la rotación, debe adaptarse a muchos tamaños iniciales y cambiar el tamaño de forma dinámica.Puede consultar
frame.height
yframe.width
dentrolayoutSubviews()
para obtener las dimensiones de CustomView como referencia. Esto se demuestra en el ejemplo siguiente.Ejemplo de subclase de UIView
Una subclase de UIView personalizada que contiene un UITextField que no es necesario implementar
init?(coder:)
.Diseño programático con diseño automático
También puede implementar el diseño utilizando el diseño automático en el código. Como no hago esto a menudo, no mostraré un ejemplo. Puede encontrar ejemplos de implementación de diseño automático en código en Stack Overflow y en otros lugares de Internet.
Marcos de diseño programático
Existen marcos de código abierto que implementan el diseño en código. Uno que me interesa pero que no he probado es LayoutKit . Fue escrito por el equipo de desarrollo de LinkedIn. Desde el repositorio de Github: "LinkedIn creó LayoutKit porque descubrimos que el diseño automático no tiene el rendimiento suficiente para jerarquías de vista complicadas en vistas desplazables".
¿Por qué poner
fatalError
eninit(coder:)
Al crear subclases de UIView que nunca se usarán en un guión gráfico o plumilla, puede introducir inicializadores con diferentes parámetros y requisitos de inicialización que el
init(coder:)
método no podría llamar . Si no falló init (codificador :) con afatalError
, podría generar problemas muy confusos en el futuro si se usa accidentalmente en un guión gráfico / nib. El fatalError afirma estas intenciones.Si desea ejecutar algún código cuando se crea la subclase, independientemente de si se crea en código o en un guión gráfico / plumilla, puede hacer algo como lo siguiente (según la respuesta de Jeff Gu Kang )
fuente
fatalError
, prohíbe iniciar esta vista con archivos xibfatalError
dentro del método dealloc y nos diga que no funciona porque esa clase debería ser un singleton. Si prefiere crear elementos de IU en código, no debería prohibir manualmente todas las demás formas. Finalmente, la pregunta es cómo crear "programáticamente sin guiones gráficos", pero no se mencionan xibs / nibs. En mi caso, necesito crear una matriz de celdas con programáticamente + xib y pasarlas,DropDownMenuKit
y de esta manera no funciona porque el autor de esta biblioteca también prohíbe xibs.Es importante que su UIView pueda crearse mediante el constructor de interfaces / guiones gráficos o desde el código. Encuentro que es útil tener un
setup
método para reducir la duplicación de cualquier código de configuración. p.ejfuente
Swift 4.0, si desea utilizar la vista desde el archivo xib, entonces esto es para usted. Creé la clase Subclase CustomCalloutView de UIView. He creado un archivo xib y en IB simplemente seleccione el propietario del archivo, luego seleccione el nombre de clase del conjunto del inspector de atributos en CustomCalloutView, luego cree una salida en su clase.
// Ahora agregándolo
fuente
Aquí hay un ejemplo de cómo suelo construir mis subclases (UIView). Tengo el contenido como variables para que se pueda acceder a ellas y modificarlas tal vez más tarde en alguna otra clase. También he mostrado cómo utilizo el diseño automático y agrego contenido.
Por ejemplo, en un ViewController tengo esta vista inicializada en ViewDidLoad () ya que solo se llama una vez cuando la vista es visible. Luego uso de estas funciones que hago aquí
addContentToView()
y despuésactivateConstraints()
de construir el contenido y las limitaciones establecidas. Si más tarde en un ViewController quiero que el color de, digamos, un botón sea rojo, simplemente lo hago en esa función específica en ese ViewController. Algo como:func tweaksome(){ self.customView.someButton.color = UIColor.red}
fuente