Solución original
- Creé un XIB y una clase llamada SomeView (usé el mismo nombre para mayor comodidad y legibilidad). Basé ambos en una UIView.
- En el XIB, cambié la clase "Propietario del archivo" a SomeView (en el inspector de identidad).
- Creé una salida UIView en SomeView.swift, vinculándola a la vista de nivel superior en el archivo XIB (lo denominé "vista" por conveniencia). Luego agregué otras salidas a otros controles en el archivo XIB según sea necesario.
- en SomeView.swift, cargué el XIB dentro del inicializador "init with code". No hay necesidad de asignar nada a "uno mismo". Tan pronto como se carga el XIB, se conectan todas las salidas, incluida la vista de nivel superior. Lo único que falta es agregar la vista superior a la jerarquía de vistas:
.
class SomeView: UIView {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
NSBundle.mainBundle().loadNibNamed("SomeView", owner: self, options: nil)
self.addSubview(self.view); // adding the top level view to the view hierarchy
}
...
}
Tenga en cuenta que de esta manera obtengo una clase que se carga desde nib. Entonces podría usar SomeView como clase siempre que UIView se pueda usar en el proyecto (en el generador de interfaces o mediante programación).
Actualización: uso de la sintaxis Swift 3
La carga de un xib en la siguiente extensión se escribe como un método de instancia, que luego puede ser utilizado por un inicializador como el anterior:
extension UIView {
@discardableResult // 1
func fromNib<T : UIView>() -> T? { // 2
guard let contentView = Bundle(for: type(of: self)).loadNibNamed(String(describing: type(of: self)), owner: self, options: nil)?.first as? T else { // 3
// xib not loaded, or its top view is of the wrong type
return nil
}
self.addSubview(contentView) // 4
contentView.translatesAutoresizingMaskIntoConstraints = false // 5
contentView.layoutAttachAll(to: self) // 6
return contentView // 7
}
}
- El uso de un valor de retorno descartable ya que la vista devuelta no tiene mayor interés para la persona que llama cuando todas las salidas ya están conectadas.
- Este es un método genérico que devuelve un objeto opcional de tipo UIView. Si no puede cargar la vista, devuelve nil.
- Intentando cargar un archivo XIB con el mismo nombre que la instancia de clase actual. Si eso falla, se devuelve nil.
- Agregar la vista de nivel superior a la jerarquía de vistas.
- Esta línea asume que estamos usando restricciones para diseñar la vista.
- Este método agrega restricciones superiores, inferiores, iniciales y finales - adjuntando la vista a "self" en todos los lados (Ver: https://stackoverflow.com/a/46279424/2274829 para más detalles)
- Volviendo a la vista de nivel superior
Y el método de llamada podría verse así:
final class SomeView: UIView { // 1.
required init?(coder aDecoder: NSCoder) { // 2 - storyboard initializer
super.init(coder: aDecoder)
fromNib() // 5.
}
init() { // 3 - programmatic initializer
super.init(frame: CGRect.zero) // 4.
fromNib() // 6.
}
// other methods ...
}
- SomeClass es una subclase de UIView que carga su contenido desde un archivo SomeClass.xib. La palabra clave "final" es opcional.
- Un inicializador para cuando la vista se usa en un guión gráfico (recuerde usar SomeClass como la clase personalizada de su vista de guión gráfico).
- Un inicializador para cuando la vista se crea mediante programación (es decir, "let myView = SomeView ()").
- Usando un marco de todos ceros ya que esta vista se presenta usando el diseño automático. Tenga en cuenta que el método "init (frame: CGRect) {..}" no se crea de forma independiente, ya que el diseño automático se utiliza exclusivamente en nuestro proyecto.
- & 6. Cargando el archivo xib usando la extensión.
Crédito: El uso de una extensión genérica en esta solución se inspiró en la respuesta de Robert a continuación.
Editar
Cambiando "ver" a "contentView" para evitar confusiones. También cambió el subíndice de matriz a ".first".
File's Owner
dar en el clavo ... ¡Gracias!fromNib()
desde dentroinit(coder aDecoder: NSCoder)
crea un bucle infinito ya que al cargar el Nib dentro delfromNib()
método se realiza una llamada a:init(coder aDecoder: NSCoder)
Mi contribución:
Entonces llámalo así:
..o incluso:
fuente
Ahora poder regresar
-> Self
rápidamente ayuda a simplificar esto un poco. Última confirmación en Swift 5.Si su
.xib
archivo y subclase comparten el mismo nombre, puede usar:Si tiene un nombre personalizado, use:
NOTA:
Si obtiene el error "vista de tipo YourType no encontrada en ...", entonces no ha establecido la clase de vista en el
.xib
archivoSeleccione su vista en el
.xib
archivo y presionecmd + opt + 4
y en laclass
entrada, ingrese su clasefuente
let myCustomView = UIView.fromNib() as? CustomView
. En este caso, seT.self
resuelve enUIView
lugar deCustomView
y no puede encontrar la punta. No estoy seguro de por qué es esto, ¿tal vez el tipo inferido para ellet
medio significa que la función se llama como aUIView
?intente seguir el código.
Editar:
fuente
Extensiones de protocolo Swift 4
Adopción
Esta implementación supone que el Nib tiene el mismo nombre que la clase UIView. Ex. MyView.xib. Puede modificar este comportamiento implementando nibName () en MyView para devolver un nombre diferente al de la implementación de extensión de protocolo predeterminada.
En xib, el propietario de los archivos es MyView y la clase de vista raíz es MyView.
Uso
fuente
Lo logré con Swift con el siguiente código:
No olvide conectar su toma de vista XIB para ver definida en swift. También puede configurar First Responder a su nombre de clase personalizado para comenzar a conectar cualquier salida adicional.
¡Espero que esto ayude!
fuente
Probado en Xcode 7 beta 4, Swift 2.0 y iOS9 SDK. El siguiente código asignará xib a la uiview. Puede usar esta vista xib personalizada en el guión gráfico y acceder también al objeto IBOutlet.
Acceda a la vista personalizada mediante programación
Código fuente: https://github.com/karthikprabhuA/CustomXIBSwift
fuente
Si tiene muchas vistas personalizadas en su proyecto, puede crear clases como
UIViewFromNib
Swift 2.3
Swift 3
Y en cada clase que acaba de heredar
UIViewFromNib
, también puede anular lanibName
propiedad si el.xib
archivo tiene un nombre diferente:fuente
Sobre la base de las soluciones anteriores.
Esto funcionará en todos los paquetes de proyectos y no necesitará genéricos al llamar desde Nib ().
Swift 2
Swift 3
Se puede usar así:
O así:
fuente
Swift 4
No olvides escribir ".primero como? CustomView".
Si quieres usar en cualquier lugar
La mejor solución es la respuesta de Robert Gummesson .
Entonces llámalo así:
fuente
fuente
self
se devuelve implícitamente de todos losinit
métodos ...Una buena manera de hacer esto con Swift es usar una enumeración.
Luego, en su código, simplemente puede usar:
fuente
Prefiero esta solución (basada en la respuesta if @ GK100):
En SomeView.swift, cargué el XIB dentro del inicializador
init
oinit:frame: CGRect
. No hay necesidad de asignar nada a "uno mismo". Tan pronto como se carga el XIB, se conectan todas las salidas, incluida la vista de nivel superior. Lo único que falta es agregar la vista superior a la jerarquía de vistas:fuente
Versión Swift 3 de la respuesta de Logan
fuente
Aquí hay una forma limpia y declarativa de cargar mediante programación una vista usando un protocolo y una extensión de protocolo (Swift 4.2):
Y puedes usar esto así:
Algunas consideraciones adicionales :
Custom Class
conjunto (y las salidas / acciones establecidas desde allí), no el propietario del archivo.fuente
Solo hago esto:
Este ejemplo utiliza la primera vista en la plumilla "MyView.xib" en el paquete principal. Pero puede variar el índice, el nombre de la punta o el paquete (principal de forma predeterminada).
Solía despertar vistas en el método de inicio de vista o hacer métodos genéricos como en las soluciones anteriores (que por cierto son inteligentes), pero ya no lo hago.
De esta manera puedo usar diferentes diseños o rasgos manteniendo la misma vista lógica y código.
Me resulta más fácil dejar que un objeto de fábrica (generalmente el viewController que usará la vista) lo cree como lo necesita. A veces necesita un propietario (por lo general, cuando la vista creada tiene una salida conectada al creador), a veces no ...
Probablemente por eso Apple no incluyó un
initFromNib
método en su clase UIView ...Para tomar un ejemplo a nivel del suelo, no sabes cómo naces. Acabas de nacer. Así son las vistas;)
fuente
Todo lo que tiene que hacer es llamar al método init en su
UIView
clase.Hazlo de esa manera:
Ahora, si desea agregar esta vista como una vista secundaria en el controlador de vista, hágalo de esa manera en el archivo view controller.swift:
fuente
Similar a algunas de las respuestas anteriores pero con una extensión más consistente de Swift3 UIView:
Lo que brinda la conveniencia de poder cargar la clase desde una plumilla autodenominada, pero también desde otras plumillas / paquetes.
fuente
Puede hacerlo a través del guión gráfico, solo agregue las restricciones adecuadas para la vista. Puede hacerlo fácilmente subclasificando cualquier vista de su propia, digamos
BaseView
:C objetivo
Swift 4
Proporciono 2 variantes sobre cómo agregar restricciones, una común y dentro del lenguaje de formato visual, seleccione la que desee :)
Además, de forma predeterminada se supone que el
xib
nombre tiene el mismo nombre que el nombre de la clase de implementación. Si no, simplemente cambiexibName
parámetro.Si subclasifica su vista desde
BaseView
, puede poner fácilmente cualquier vista y especificar la clase en IB.fuente
fuente
Versión más potente basada en la respuesta de Logan
Y puedes usar como
fuente
La implementación más conveniente. Aquí necesita dos métodos para regresar directamente al objeto de su clase, no a UIView.
Ejemplo:
fuente
Si desea que la subclase Swift UIView sea completamente autónoma y tenga la capacidad de instanciarse usando init o init (frame :) sin exponer los detalles de implementación de usar un Nib, entonces puede usar una extensión de protocolo para lograr esto. Esta solución evita la jerarquía de UIView anidada como lo sugieren muchas de las otras soluciones.
fuente
fuente
Prefiero la extensión a continuación
La diferencia entre esta y la extensión con la respuesta más alta es que no necesita almacenarla de forma constante o variable.
fuente
fuente