personalizado margen manejo hacer formatos formato desfasar cómo cuadro como celdas objective-c ios uitableview storyboard

objective c - margen - En un guión gráfico, ¿cómo hago una celda personalizada para usar con varios controladores?



manejo de celdas en excel 2013 (6)

Estoy tratando de usar guiones gráficos en una aplicación en la que estoy trabajando. En la aplicación hay Listas y Usuarios, y cada uno contiene una colección del otro (miembros de una lista, listas que pertenecen a un usuario). Entonces, en consecuencia, tengo clases ListCell y UserCell . El objetivo es que sean reutilizables en toda la aplicación (es decir, en cualquiera de mis controladores de Tableview).

Ahí es donde me encuentro con un problema.

¿Cómo creo una celda de vista de tabla personalizada en el guión gráfico que se puede reutilizar en cualquier controlador de vista?

Aquí están las cosas específicas que he probado hasta ahora.

  • En el Controlador n. ° 1, se agregó una celda prototipo, se estableció la clase en mi subclase UITableViewCell , se estableció la identificación de reutilización, se agregaron las etiquetas y se conectaron a los puntos de venta de la clase. En el Controlador n. ° 2, agregó una celda de prototipo vacía, configúrela en la misma clase y reutilice la identificación como antes. Cuando se ejecuta, las etiquetas nunca aparecen cuando las celdas se muestran en el Controlador # 2. Funciona bien en el controlador # 1.

  • Diseñó cada tipo de celda en un NIB diferente y se conectó a la clase de celda apropiada. En el guión gráfico, se agregó una celda de prototipo vacía, se estableció su clase y se reutilizó la identificación para referirse a mi clase de celda. En los métodos viewDidLoad los controladores, se registraron esos archivos NIB para el ID de reutilización. Cuando se muestran, las celdas de ambos controladores estaban vacías como el prototipo.

  • Los prototipos guardados en ambos controladores vacían y configuran la clase y reutilizan la identificación a mi clase de celda. Construyó la IU de las celdas completamente en código. Las celdas funcionan perfectamente en todos los controladores.

En el segundo caso, sospecho que el prototipo siempre está anulando el NIB y si eliminara las celdas del prototipo, el registro de mi NIB para el ID de reutilización funcionaría. Pero entonces no podría configurar segmentos de las celdas a otros marcos, que es realmente el punto de uso de guiones gráficos.

Al final del día, quiero dos cosas: cablear flujos basados ​​en TableView en el guión gráfico y definir diseños de celdas visualmente en lugar de en código. No puedo ver cómo llegar a los dos hasta ahora.


A pesar de la gran respuesta de BJ Homer, siento que tengo una solución. En cuanto a mis pruebas, funciona.

Concepto: Crear una clase personalizada para la celda xib. Allí puede esperar un evento táctil y realizar la programación mediante programación. Ahora todo lo que necesitamos es una referencia al controlador que realiza el Segue. Mi solución es configurarlo en tableView:cellForRowAtIndexPath:

Ejemplo

Tengo un DetailedTaskCell.xib contiene una celda de tabla que me gustaría usar en varias vistas de tabla:

Hay una clase personalizada TaskGuessTableCell para esa celda:

Aquí es donde ocurre la magia.

// TaskGuessTableCell.h #import <Foundation/Foundation.h> @interface TaskGuessTableCell : UITableViewCell @property (nonatomic, weak) UIViewController *controller; @end // TashGuessTableCell.m #import "TaskGuessTableCell.h" @implementation TaskGuessTableCell @synthesize controller; - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { NSIndexPath *path = [controller.tableView indexPathForCell:self]; [controller.tableView selectRowAtIndexPath:path animated:NO scrollPosition:UITableViewScrollPositionNone]; [controller performSegueWithIdentifier:@"FinishedTask" sender:controller]; [super touchesEnded:touches withEvent:event]; } @end

Tengo varios Segues pero todos tienen el mismo nombre: "FinishedTask" Tarea "FinishedTask" . Si necesita ser flexible aquí, sugiero agregar otra propiedad.

El ViewController se ve así:

// LogbookViewController.m #import "LogbookViewController.h" #import "TaskGuessTableCell.h" @implementation LogbookViewController - (void)viewDidLoad { [super viewDidLoad] // register custom nib [self.tableView registerNib:[UINib nibWithNibName:@"DetailedTaskCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"DetailedTaskCell"]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { TaskGuessTableCell *cell; cell = [tableView dequeueReusableCellWithIdentifier:@"DetailedTaskCell"]; cell.controller = self; // <-- the line that matters // if you added the seque property to the cell class, set that one here // cell.segue = @"TheSegueYouNeedToTrigger"; cell.taskTitle.text = [entry title]; // set other outlet values etc. ... return cell; } - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if([[segue identifier] isEqualToString:@"FinishedTask"]) { // do what you have to do, as usual } } @end

Puede haber formas más elegantes de lograr lo mismo pero, ¡funciona! :)


BJ Homer ha dado una excelente explicación de lo que está pasando.

Desde un punto de vista práctico, agregaría que, dado que no puede tener celdas como xibs Y conecte segmentos, el mejor para elegir es tener la celda como xib: las transiciones son mucho más fáciles de mantener que los diseños y propiedades de celdas en múltiples lugares , y es probable que sus segmentos sean diferentes de sus diferentes controladores de todos modos. Puede definir el segmento directamente desde su controlador de vista de tabla al siguiente controlador y realizarlo en código. .

Una nota adicional es que tener su celda como un archivo xib separado le impide poder conectar cualquier acción, etc. directamente al controlador de vista de tabla (de todos modos, no he resuelto este problema, no puede definir el propietario del archivo como algo significativo ). Estoy trabajando alrededor de esto definiendo un protocolo que se espera que el controlador de vista de tabla de la celda cumpla y agregue el controlador como una propiedad débil, similar a un delegado, en cellForRowAtIndexPath.


Como yo lo entiendo, quieres:

  1. Diseñe una celda en IB que se pueda usar en múltiples escenas del guión gráfico.
  2. Configure segmentos de guión gráfico únicos desde esa celda, dependiendo de la escena en la que se encuentre la celda.

Desafortunadamente, actualmente no hay manera de hacer esto. Para comprender por qué sus intentos anteriores no funcionaron, necesita comprender más sobre cómo funcionan los guiones gráficos y las celdas de vista de tabla de prototipo. (Si no te importa por qué estos otros intentos no funcionaron, siéntete libre de irte ahora. No tengo soluciones mágicas para ti, aparte de sugerir que presentes un error).

Un storyboard no es, en esencia, mucho más que una colección de archivos .xib. Cuando carga un controlador de vista de tabla que tiene algunas celdas prototipo fuera de un guión gráfico, esto es lo que sucede:

  • Cada célula prototipo es en realidad su propia mini-pluma incrustada. Entonces, cuando el controlador de vista de tabla se está cargando, se ejecuta a través de cada uno de los nibs y llamadas de la celda prototipo -[UITableView registerNib:forCellReuseIdentifier:] .
  • La vista de tabla pide al controlador las celdas.
  • Probablemente llame a -[UITableView dequeueReusableCellWithIdentifier:]
  • Cuando solicita una celda con un identificador de reutilización dado, verifica si tiene una punta registrada. Si lo hace, crea una instancia de esa celda. Esto se compone de los siguientes pasos:

    1. Mire la clase de la celda, como se define en la punta de la celda. Llame a [[CellClass alloc] initWithCoder:] .
    2. El método -initWithCoder: recorre y agrega subvistas y establece las propiedades que se definieron en la punta. ( IBOutlet probable que IBOutlet s también se IBOutlet aquí, aunque no lo he probado; puede suceder en -awakeFromNib )
  • Tú configuras tu celular como quieras.

Lo importante a destacar aquí es que hay una distinción entre la clase de la celda y el aspecto visual de la celda. Podría crear dos celdas prototipo separadas de la misma clase, pero con sus subvistas distribuidas de manera completamente diferente. De hecho, si usa los estilos predeterminados de UITableViewCell , esto es exactamente lo que está sucediendo. El estilo "Predeterminado" y el estilo "Subtítulo", por ejemplo, están representados por la misma clase UITableViewCell .

Esto es importante : la clase de la celda no tiene una correlación de uno a uno con una jerarquía de vista particular. La jerarquía de vistas está determinada completamente por lo que está en la celda prototipo que se registró con este controlador en particular.

Tenga en cuenta, también, que el identificador de reutilización de la celda no se registró en algún dispensario de celda global. El identificador de reutilización solo se utiliza en el contexto de una única instancia de UITableView .

Dada esta información, veamos lo que sucedió en sus intentos anteriores.

En el Controlador n. ° 1, se agregó una celda prototipo, se estableció la clase en mi subclase UITableViewCell, se estableció la identificación de reutilización, se agregaron las etiquetas y se conectaron a los puntos de venta de la clase. En el Controlador n. ° 2, agregó una celda de prototipo vacía, configúrela en la misma clase y reutilice la identificación como antes. Cuando se ejecuta, las etiquetas nunca aparecen cuando las celdas se muestran en el Controlador # 2. Funciona bien en el controlador # 1.

Esto es lo esperado. Si bien ambas celdas tenían la misma clase, la jerarquía de vista que se pasó a la celda en el Controlador # 2 carecía por completo de subvistas. Así que tienes una celda vacía, que es exactamente lo que pones en el prototipo.

Diseñó cada tipo de celda en un NIB diferente y se conectó a la clase de celda apropiada. En el guión gráfico, se agregó una celda de prototipo vacía, se estableció su clase y se reutilizó la identificación para referirse a mi clase de celda. En los métodos viewDidLoad de los controladores, se registraron esos archivos NIB para el ID de reutilización. Cuando se muestran, las celdas de ambos controladores estaban vacías como el prototipo.

De nuevo, esto es lo esperado. El identificador de reutilización no se comparte entre escenas del guión gráfico o nibs, por lo que el hecho de que todas estas celdas distintas tuvieran el mismo identificador de reutilización no tenía sentido. La celda que obtienes de la vista de tabla tendrá una apariencia que coincide con la celda prototipo en esa escena del guión gráfico.

Sin embargo, esta solución estaba cerca. Como notó, simplemente puede llamar a -[UITableView registerNib:forCellReuseIdentifier:] , pasando el UINib contiene la celda, y obtendría la misma celda. (Esto no se debe a que el prototipo estaba "sobrescribiendo" la punta; simplemente no había registrado la punta con la vista de tabla, por lo que aún estaba mirando la punta incrustada en el guión gráfico). Desafortunadamente, hay un error con este enfoque: no hay forma de conectar el guión gráfico a una celda en una punta independiente.

Los prototipos guardados en ambos controladores vacían y configuran la clase y reutilizan la identificación a mi clase de celda. Construyó la IU de las celdas completamente en código. Las celdas funcionan perfectamente en todos los controladores.

Naturalmente. Con suerte, esto no es sorprendente.

Entonces, por eso no funcionó. Puede diseñar sus celdas en puntas independientes y usarlas en múltiples escenas del guión gráfico; simplemente no puedes conectar los guiones gráficos a esas celdas. Con suerte, sin embargo, has aprendido algo en el proceso de leer esto.


Encontré una forma de cargar la celda para el mismo VC, sin probar los segmentos. Esto podría ser una solución para crear la celda en una punta separada.

Digamos que usted tiene un VC y 2 tablas y desea diseñar una celda en el guión gráfico y usarla en ambas tablas.

(por ejemplo, una tabla y un campo de búsqueda con un UISearchController con una tabla de resultados y desea utilizar la misma celda en ambos)

Cuando el controlador le pide a la celda que haga esto:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString * identifier = @"CELL_ID"; ContactsCell *cell = [self.YOURTABLEVIEW dequeueReusableCellWithIdentifier:identifier]; // Ignore the "tableView" argument }

Y aquí tienes tu celular del guión gráfico.


Estaba buscando esto y encontré esta respuesta por Richard Venable. Esto funciona para mi.

iOS 5 incluye un nuevo método en UITableView: registerNib: forCellReuseIdentifier:

Para usarlo, ponga un UITableViewCell en una punta. Tiene que ser el único objeto raíz en la punta.

Puede registrar la punta después de cargar su tableView, luego, cuando llame a dequeueReusableCellWithIdentifier: con el identificador de celda, la extraerá de la punta, como si hubiera usado una celda prototipo de Storyboard.


Swift 3

BJ Homer dio una excelente explicación, me ayuda a entender el concepto. Para make a custom cell reusable in storyboard , que se puede utilizar en cualquier TableViewController, tenemos que mix the Storyboard and xib enfoque mix the Storyboard and xib . Supongamos que tenemos una celda llamada CustomCell que se utilizará en TableViewControllerOne y TableViewControllerTwo . Lo estoy haciendo en pasos.
1. Archivo> Nuevo> Haga clic en Archivo> Seleccionar clase de Cocoa Touch> haga clic en Siguiente> Dar nombre de su clase (por ejemplo, CustomCell )> seleccione Subclase como UITableVieCell> Marque la casilla de verificación también crear archivo XIB y presione Siguiente.
2. Personalice la celda como desee y establezca el identificador en el inspector de atributos para celda, aquí estableceremos como CellIdentifier . Este identificador se utilizará en su ViewController para identificar y reutilizar la celda.
3. Ahora solo tenemos que register this cell en nuestro ViewController viewDidLoad . No hay necesidad de ningún método de inicialización.
4. Ahora podemos usar esta celda personalizada en cualquier tableView.

En TableViewControllerOne

let reuseIdentifier = "CellIdentifier" override func viewDidLoad() { super.viewDidLoad() tableView.register(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: reuseIdentifier) } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier:reuseIdentifier, for: indexPath) as! CustomCell return cell! }