Estoy tratando de hacer algo un poco elaborado, pero algo que debería ser posible. Así que aquí hay un desafío para todos ustedes expertos (este foro es un paquete de muchos de ustedes :)).
Estoy creando un "componente" del Cuestionario, que quiero cargar en un NavigationContoller
(mi QuestionManagerViewController
). El "componente" es un "vacío" UIViewController
, que puede cargar diferentes vistas dependiendo de la pregunta que deba responderse.
La forma en que lo hago es:
- Cree el objeto Question1View como una
UIView
subclase, definiendo algunosIBOutlets
. - Cree (usando Interface Builder) el
Question1View.xib
(AQUÍ ES DONDE ESTÁ MI PROBLEMA PROBABLEMENTE ). Configuré tanto elUIViewController
y elUIView
para ser de clase Question1View. - Enlace los puntos de venta con el componente de la vista (usando IB).
Anulo el
initWithNib
de miQuestionManagerViewController
para lucir así:- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { if (self = [super initWithNibName:@"Question1View" bundle:nibBundleOrNil]) { // Custom initialization } return self; }
Cuando ejecuto el código, recibo este error:
2009-05-14 15: 05: 37.152 iMobiDines [17148: 20b] *** Finalización de la aplicación debido a una excepción no detectada '
NSInternalInconsistencyException
', razón: '-[UIViewController _loadViewFromNibNamed:bundle:]
cargó la plumilla "Question1View" pero el punto de vista no estaba configurado ".
Estoy seguro de que hay una manera de cargar la vista usando el archivo nib, sin necesidad de crear una clase viewController.
fuente
Gracias a todos. Encontré una manera de hacer lo que quería.
UIView
con losIBOutlet
s que necesitas.UIViewController
(no hay una subclase personalizada, sino la "real"). La vista del propietario del archivo está conectada a la vista principal y su clase se declara como la del paso 1).IBOutlet
s.El
DynamicViewController
puede ejecutar su lógica para decidir qué vista / xib cargar. Una vez que ha tomado la decisión, en elloadView
método ponga algo como esto:¡Eso es!
El
loadNibNamed
método del paquete principal se encargará de inicializar la vista y crear las conexiones.Ahora el ViewController puede mostrar una vista u otra dependiendo de los datos en la memoria, y la pantalla "principal" no necesita molestarse con esta lógica.
fuente
No estoy seguro de qué están hablando algunas de las respuestas, pero necesito poner esta respuesta aquí para cuando busque en Google la próxima vez. Palabras clave: "Cómo cargar una UIView desde una punta" o "Cómo cargar una UIView desde un NSBundle".
Aquí está el código casi al 100% directamente del libro Apress Beginning iPhone 3 (página 247, "Uso de la nueva celda de vista de tabla"):
Esto supone que tiene una
UIView
subclase llamadaBlah
, una punta llamadaBlah
que contiene unaUIView
que tiene su clase establecidaBlah
.Categoría: NSObject + LoadFromNib
Extensión rápida
Y un ejemplo en uso:
fuente
isKindOf
está protegido de los cambios de estructura del paquete.assert
sería probablemente una mejor solución. De esta manera solo ocultarás el problema.for
bucle. Lo complementa.Para todos aquellos que necesitan administrar más de una instancia de la vista personalizada, es decir, una Colección Outlet , fusioné y personalicé las respuestas @Gonso, @AVeryDev y @Olie de esta manera:
Cree un personalizado
MyView : UIView
y configúrelo como " Clase personalizada " de la raízUIView
en el XIB deseado ;Cree todos los puntos de venta que necesite
MyView
(hágalo ahora porque después del punto 3 el IB le propondrá conectar los puntos de venta a laUIViewController
vista personalizada y no a la vista personalizada como queramos);Establezca su
UIViewController
como " Propietario del archivo " de la vista personalizada XIB ;En el
UIViewController
añadir nuevoUIViews
para cada instancia deMyView
que desee, y conectarlos aUIViewController
la creación de una colección de salida : estos puntos de vista actuarán como puntos de vista "contenedor" para las instancias de vista personalizada;Finalmente, en el
viewDidLoad
de suUIViewController
agregue las siguientes líneas:fuente
Usaría UINib para crear una instancia de UIView personalizada para ser reutilizada
Los archivos necesarios en este caso son MyCustomView.xib , MyCustomViewClass.h y MyCustomViewClass.m Tenga en cuenta que
[UINib instantiateWithOwner]
devuelve una matriz, por lo que debe usar el elemento que refleja la UIView que desea reutilizar. En este caso es el primer elemento.fuente
No debe configurar la clase de su controlador de vista para que sea una subclase de
UIView
Interface Builder. Eso es definitivamente al menos parte de su problema. Déjalo comoUIViewController
una subclase o alguna otra clase personalizada que tengas.En cuanto a cargar solo una vista desde un xib, suponía que tenía que tener algún tipo de controlador de vista (incluso si no se extiende
UIViewController
, que puede ser demasiado pesado para sus necesidades) configurado como Propietario del archivo en la interfaz Builder si quieres usarlo para definir tu interfaz. Investigué un poco para confirmar esto también. Esto se debe a que, de lo contrario, no habría forma de acceder a ninguno de los elementos de la interfaz en elUIView
, ni habría una forma de tener sus propios métodos en el código desencadenados por eventos.Si usa a
UIViewController
como Propietario de su archivo para sus vistas, puede usarloinitWithNibName:bundle:
para cargarlo y recuperar el objeto del controlador de vista. En IB, asegúrese de configurar laview
salida a la vista con su interfaz en el xib. Si usa algún otro tipo de objeto como propietario de su archivo, deberá usarNSBundle
elloadNibNamed:owner:options:
método de '' para cargar la punta, pasando una instancia del propietario de archivo al método. Todas sus propiedades se establecerán correctamente de acuerdo con los puntos de venta que defina en IB.fuente
También puede usar initWithNibName de UIViewController en lugar de loadNibNamed. Es más simple, me parece.
Ahora solo tiene que crear MySubView.xib y MySubView.h / m. En MySubView.xib establezca la clase Propietario del archivo en UIViewController y vea la clase en MySubView.
Puede posicionar y dimensionar el
subview
archivo xib principal.fuente
Esta es una gran pregunta (+1) y las respuestas fueron casi útiles;) Lo siento muchachos, pero tuve un montón de tiempo trabajando en esto, aunque tanto Gonso como AVeryDev dieron buenos consejos. Con suerte, esta respuesta ayudará a otros.
MyVC
es el controlador de vista que contiene todo esto.MySubview
es la vista que queremos cargar desde un xibMySubView
que tenga el tamaño y la forma correctos y se coloque donde desee.En MyVC.h, tengo
En MyVC.m,
@synthesize mySubView;
y no olvides lanzarlodealloc
.UIView *view
(puede ser innecesario, pero funcionó para mí). Sintetizar y liberarlo en .mMySubview
y vincule la propiedad de vista a su vista.IBOutlet
's como deseeDe vuelta en MyVC.m, tengo
Lo más difícil para mí fue: las sugerencias en las otras respuestas cargaron mi vista desde el xib, pero NO reemplazaron la vista en MyVC (¡duh!) - Tuve que cambiar eso por mi cuenta.
Además, para obtener acceso a
mySubview
los métodos de, laview
propiedad en el archivo .xib debe establecerse enMySubview
. De lo contrario, vuelve como un viejoUIView
.Si hay una manera de cargar
mySubview
directamente desde su propio xib, eso sería genial, pero esto me llevó a donde necesitaba estar.fuente
Esto es algo que debería ser más fácil. Terminé extendiendo
UIViewController
y agregando unloadNib:inPlaceholder:
selector. Ahora puedo decirAquí está el código para la categoría (hace el mismo rigamarole descrito por Gonso):
fuente
En rápido
En realidad, mi resolución a este problema fue cargar la vista en viewDidLoad en mi CustonViewController donde quería usar la vista así:
¡No cargue la vista en un
loadView()
método! El método loadView sirve para cargar la vista para su ViewController personalizado.fuente
Yo también quería hacer algo similar, esto es lo que encontré: (SDK 3.1.3)
Tengo un controlador de vista A (propiedad de un controlador Nav) que carga VC B al presionar un botón:
En AViewController.m
Ahora VC B tiene su interfaz de Bnib, pero cuando se presiona un botón, quiero ir a un 'modo de edición' que tiene una interfaz de usuario separada de una punta diferente, pero no quiero un nuevo VC para el modo de edición, Quiero que la nueva punta se asocie con mi B VC existente.
Entonces, en BViewController.m (en el método de presionar un botón)
Luego, en otro botón, presione (para salir del modo de edición):
y vuelvo a mi Bnib original.
Esto funciona bien, pero tenga en cuenta que mi EditMode.nib solo tiene 1 obj de nivel superior, un obj UIView. No importa si el propietario del archivo en este plumín está configurado como BViewController o el NSObject predeterminado, PERO asegúrese de que la salida de visualización en el propietario del archivo NO esté configurada en nada. Si es así, recibo un bloqueo exc_bad_access y xcode procede a cargar 6677 cuadros de pila que muestran un método interno UIView repetidamente llamado ... por lo que parece un bucle infinito. (Sin embargo, View Outlet está configurado en mi Bnib original)
Espero que esto ayude.
fuente
Hice una categoría que me gusta:
UIView+NibInitializer.h
UIView+NibInitializer.m
Entonces, llame así:
Use un nombre de plumín si su plumín tiene un nombre diferente al de su clase.
Para anularlo en sus subclases para un comportamiento adicional, podría verse así:
fuente
Para usuarios de Swift con opción designable:
UIView
subclase personalizada y un archivo xib , que nombraremos después de nuestro propio nombre de clase: en nuestro caso, MemeView. Dentro de la clase Meme View, recuerde definirla como designable con el@IBDesignable
atributo antes de la declaración de claseRecuerde configurar el Propietario del archivo en el xib con nuestra
UIView
subclase personalizada en el panel del Inspector de independenciaEn el archivo xib ahora podemos construir nuestra interfaz, hacer restricciones, crear salidas, acciones, etc.
Necesitamos implementar algunos métodos en nuestra clase personalizada para abrir el xib una vez inicializado
class XibbedView: UIView {
}
En nuestra clase personalizada también podemos definir algunas propiedades inspeccionables para tener control total sobre ellas desde el generador de interfaces
@IBDesignable class MemeView: XibbedView {
}
Pocos ejemplos:
Si necesitamos agregar más información a la vista mientras se muestra dentro de un guión gráfico u otro xib, para hacer eso podemos implementar
prepareForInterfaceBuilder()
, este método se ejecutará solo al abrir el archivo en el generador de interfaces. Si hizo todo lo que escribí pero nada funciona, esta es una forma de depurar una vista sigle agregando puntos de interrupción en su implementación. Aquí está la jerarquía de vistas.Espero que esto ayude a descargar una muestra completa aquí
fuente
let nib = loadNib(nibName)
esta es una instancia de XibbedView, si llama `` `addSubview (nib)` `` ¿entonces está agregando una instancia de XibbedView a otra instancia de XibbedView?Encontré que esta publicación de blog de Aaron Hillegass (autor, instructor, Cocoa ninja) es muy esclarecedora. Incluso si no adopta su enfoque modificado para cargar archivos NIB a través de un inicializador designado, probablemente al menos obtendrá una mejor comprensión del proceso que está sucediendo. ¡He estado usando este método últimamente con gran éxito!
fuente
La respuesta anterior no tiene en cuenta un cambio en la estructura NIB (XIB) que se produjo entre 2.0 y 2.1 del SDK de iPhone. El contenido del usuario ahora comienza en el índice 0 en lugar de 1.
Puede usar la macro 2.1 que es válida para todas las versiones 2.1 y superiores (son dos guiones bajos antes de IPHONE:
Utilizamos una técnica similar a esta para la mayoría de nuestras aplicaciones.
Barney
fuente
Tenía razones para hacer lo mismo (cargar programáticamente una vista desde un archivo XIB), pero necesitaba hacerlo completamente desde el contexto de una subclase de una subclase de a
UIView
(es decir, sin involucrar al controlador de vista de ninguna manera). Para hacer esto, creé este método de utilidad:Luego lo llamo desde el
initWithFrame
método de mi subclase así:Publicado para interés general; Si alguien ve algún problema sin hacerlo de esta manera, hágamelo saber.
fuente
Aquí hay una manera de hacerlo en Swift (actualmente escribiendo Swift 2.0 en XCode 7 beta 5).
Desde su
UIView
subclase que establezca como "Clase personalizada" en el Creador de interfaces, cree un método como este (mi subclase se llama RecordingFooterView):Entonces puedes llamarlo así:
let recordingFooterView = RecordingFooterView.loadFromNib()
fuente
Ninguna de las respuestas explica cómo crear el XIB independiente que es la raíz de esta pregunta. No hay
Xcode 4
opción para "Crear nuevo archivo XIB".Para hacer esto
Esto puede parecer simple, pero puede ahorrarle unos minutos buscando porque la palabra "XIB" no aparece en ningún lado.
fuente
@AVeryDev
6) Para adjuntar la vista cargada a la vista del controlador de vista:
Presumiblemente, es necesario eliminarlo de la vista para evitar pérdidas de memoria.
Para aclarar: el controlador de vista tiene varios IBOutlets, algunos de los cuales están conectados a elementos en el archivo de plumín original (como de costumbre), y algunos están conectados a elementos en el plumín cargado. Ambas puntas tienen la misma clase de propietario. La vista cargada se superpone a la original.
Sugerencia: establezca la opacidad de la vista principal en la punta cargada a cero, luego no ocultará los elementos de la punta original.
fuente
Después de pasar muchas horas, forjé la siguiente solución. Siga estos pasos para crear personalizados
UIView
.1) Crear clase myCustomView heredada de UIView .
2) Crear .xib con el nombre myCustomView .
3) Cambie la clase de UIView dentro de su archivo .xib, asigne myCustomView Class allí.
4) Crear IBOutlets
5) Cargue .xib en myCustomView * customView . Use el siguiente código de muestra.
fuente
Versión más corta:
fuente
Tengo una convención de nombrar xibs con vistas en ellos igual que la vista. Lo mismo que uno haría para un controlador de vista. Entonces, no tengo que escribir los nombres de las clases en el código. Cargo una UIView desde un archivo plumín con el mismo nombre.
Ejemplo para una clase llamada MyView.
En su código, cree un nuevo MyView como este:
MyView * myView = [MyView nib_viewFromNibWithOwner: propietario];
Aquí está la categoría para esto:
Luego conectaba los botones con acciones del controlador que estoy usando, y establecía cosas en las etiquetas usando los puntos de venta en mi subclase de vista personalizada.
fuente
Para cargar mediante programación una vista desde una punta / xib en Swift 4:
fuente
Terminé agregando una categoría a UIView para esto:
explicación aquí: viewcontroller es menos carga de vista en ios y mac
fuente