2011-04-11 8 views
5

Numerosas personas han formulado una pregunta similar, pero las respuestas fueron lo suficientemente vagas o no en la dirección en que necesitaba las cosas, así que intentaré hacer esto de la manera más concreta posible. El contexto de esta pregunta es para el desarrollo de iOS con XCode 4.UIView personalizado configurado con InterfaceBuilder

Tengo una aplicación en la que utilizo el mismo widget varias veces. En este ejercicio simple, el widget será un cuadro rojo de tamaño fijo con una etiqueta en la parte superior que cambiará el controlador de vista raíz, pero se puede imaginar que tiene muchas imágenes y ScrollViews y se ve bastante espectacular. Este último punto es clave, porque los diseñadores artísticos que no codifican quieren poder ajustar esta vista globalmente sin tener que hacer lo mismo una y otra vez en cada pieza duplicada de la IU.

En la aplicación he reemplazado las ImageViews y ScrollViews que solían componer el widget con una sola UIView, y utilizando InterfaceBuilder establecí la clase personalizada en Widget. Tengo enchufes en el controlador de vista raíz para estos objetos de widgets correctamente conectados. La clase Widget es una subclase de UIView, y el código es el siguiente:

@interface Widget : UIView { 
    UILabel  *label; 
} 

@property (nonatomic, retain) IBOutlet UILabel *label; 
@property (nonatomic, copy) NSString *labelName; 
@end 


@implementation Widget 
@synthesize label, labelName; 

- (id)initWithCoder:(NSCoder *)aDecoder { 
    if ((self = [super initWithCoder:aDecoder])) { 
     // This is the code that I want to disappear  
     CGRect pos = CGRectMake(5, 5, 90, 30); 
     label = [[UILabel alloc] initWithFrame:pos]; 
     [self addSubview:label]; 
     self.backgroundColor = [UIColor redColor]; 
    } 
    return self; 
} 

- (NSString *)labelName { 
    return label.text; 
} 

// This live updates the label in this custom view 
- (void)setLabelName:(NSString *)name { 
    label.text = name; 
} 

- (void)dealloc { 
    [super dealloc]; 
} 
@end 

El código funciona muy bien, y puedo vivir actualizar el texto en las vistas personalizadas del controlador principal vista. Sin embargo, las cuatro líneas de código que están en initWithCoder son el problema. ¿Recuerdas a los diseñadores? Los tengo en el punto en el que pueden usar magia con Interface Builder, pero no puedo imaginar cómo hacer que UIView se cargue desde un plumín que han diseñado. Intentar manualmente y replicar el posicionamiento y las propiedades de un solo artículo no es demasiado emocionante y lleva mucho tiempo (y sí, me doy cuenta de que ya habría terminado si no hubiera escrito esta publicación).

De manera muy simple, ¿cómo puedo tomar un archivo .xib arbitrario y hacer que haga el trabajo que hice a mano en initWithCoder? Supongo que será trivial en ese momento conectar el IBOutlet para UILabel, pero por favor coméntelo si soy demasiado optimista.

Como una pregunta secundaria, una vez que esté funcionando en la interfaz de usuario real, tendré cosas como, UIScrollViews conectado. ¿Se convierte Widget en UIScrollViewDelegate o dónde se estaciona este código? El controlador de la vista raíz no debe tener en cuenta esto, pero se siente inapropiado poner el código I tradicionalmente puesto en un Controlador de Vista en un objeto UIView.

+0

Si su artilugio es más que un contenedor tonto para sus vistas, ¿por qué no convertirlo en un controlador de vista? – jrturton

Respuesta

0

Sí, debe conectar un IBOutlet con la etiqueta y, a continuación, los diseñadores pueden colocar la etiqueta de Interface Builder.

En cuanto UIScrollViewDelegate, también se debe establecer un IBOutlet para la vista de desplazamiento, y luego dentro del controladorhacer widgetView.scrollView.delegate = self, para establecer su controlador actual como un delegado de la vista de desplazamiento.

Como alternativa, puede hacer que el Widget vea a un delegado de la vista de desplazamiento, pero en mi opinión rompería el cumplimiento de MVC haciendo eso (el código que maneja los eventos de vista de desplazamiento es el código del controlador).

+0

Así que después de crear el archivo .xib con un UIView (digamos 100x200) que contiene un UILabel colocado en el UIView, necesito vincular esto junto con el 'widget.h/.cpp'. Una de las ideas fallidas es que el inspector de identidad establezca que ** Clase personalizada ** del Propietario de archivo sea un 'Aparato '. Luego puedo configurar ** Referencing Outlet ** en la etiqueta para que sea la propiedad 'label' del Propietario del Archivo. Después de comentar las cuatro líneas de código en 'initWithCoder', nada de lo que haga hará que el contenido de .xib aparezca en un controlador de vista que tenga objetos de widget en él. Solo espero que haya un paso final obvio que me estoy perdiendo. – Waldo

0

En cuanto a su primera pregunta, creo que lo que busca es la siguiente:

Widget *widget = nil; 
NSArray *nibItems = [[NSBundle mainBundle] loadNibNamed:@"Widget" owner:self options:nil]; 
for (id o in nibItems) { 
    if ([o isTypeOfClass:[Widget class]]) { 
     widget = (Widget *)id; 
    } 
} 

// Do whatever you want with the Widget... 

cargarlo desde la punta a través del haz preservará sus diseñadores trabajan en el constructor de interfaces, y dará lugar a una llamada para iniciarConCoder.

En cuanto a la segunda pregunta, tiene dos opciones.Puede establecer la propiedad de delegado de UIScrollView dentro del plumín (es un atributo accesible por IB) o configurarlo manualmente en código en su método initWithCoder. Depende de cuál sea el comportamiento deseado.

4

Declare un IBOutlet (IBOutlet UIView * Widget;) en su controlador. Coloque la vista de widgets (del diseñador) en el xib de su controlador (si su controlador no tiene xib, entonces puede crear o especificar un nuevo xib para su controlador). A continuación, conecte esta vista al IBOutlet anterior. Si desea evitar el enganche de etiquetas, scrollview, etc. siempre que el diseñador realice cambios, debe reemplazar todo el xib en lugar de simplemente reemplazar la vista.

Cuestiones relacionadas