uitableviewdatasource uitableviewcontroller uitableviewcell example ios cocoa-touch uitableview

ios - uitableviewcell - uitableviewcontroller swift 4



¿Puede animar un cambio de altura en un UITableViewCell cuando se selecciona? (19)

Estoy usando un UITableView en mi aplicación de iPhone y tengo una lista de personas que pertenecen a un grupo. Me gustaría que cuando el usuario haga clic en una persona en particular (seleccionando así la celda), la celda crezca en altura para mostrar varios controles de interfaz de usuario para editar las propiedades de esa persona.

es posible?


Acabo de resolver este problema con un pequeño truco:

static int s_CellHeight = 30; static int s_CellHeightEditing = 60; - (void)onTimer { cellHeight++; [tableView reloadData]; if (cellHeight < s_CellHeightEditing) heightAnimationTimer = [[NSTimer scheduledTimerWithTimeInterval:0.001 target:self selector:@selector(onTimer) userInfo:nil repeats:NO] retain]; } - (CGFloat)tableView:(UITableView *)_tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if (isInEdit) { return cellHeight; } cellHeight = s_CellHeight; return s_CellHeight; }

Cuando necesito expandir la altura de la celda, establezco isInEdit = YES y llamo el método [self onTimer] y anima el crecimiento de la celda hasta que alcance el valor de s_CellHeightEditing :-)


Agregar una propiedad para realizar un seguimiento de la celda seleccionada

@property (nonatomic) int currentSelection;

Establézcalo en un valor de centinela en (por ejemplo) viewDidLoad , para asegurarse de que UITableView comience en la posición "normal"

- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. //sentinel self.currentSelection = -1; }

En heightForRowAtIndexPath puede establecer la altura que desee para la celda seleccionada

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ int rowHeight; if ([indexPath row] == self.currentSelection) { rowHeight = self.newCellHeight; } else rowHeight = 57.0f; return rowHeight; }

En didSelectRowAtIndexPath , guarda la selección actual y guarda una altura dinámica, si es necesario

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // do things with your cell here // set selection self.currentSelection = indexPath.row; // save height for full text label self.newCellHeight = cell.titleLbl.frame.size.height + cell.descriptionLbl.frame.size.height + 10; // animate [tableView beginUpdates]; [tableView endUpdates]; } }

En didDeselectRowAtIndexPath , didDeselectRowAtIndexPath establecer el índice de selección en el valor de centinela y anime la celda a su forma normal

- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath { // do things with your cell here // sentinel self.currentSelection = -1; // animate [tableView beginUpdates]; [tableView endUpdates]; } }


Aquí está mi código de la subclase UITableView personalizada, que amplía UITextView en la celda de la tabla, sin recargar (y sin el foco del teclado):

- (void)textViewDidChange:(UITextView *)textView { CGFloat textHeight = [textView sizeThatFits:CGSizeMake(self.width, MAXFLOAT)].height; // Check, if text height changed if (self.previousTextHeight != textHeight && self.previousTextHeight > 0) { [self beginUpdates]; // Calculate difference in height CGFloat difference = textHeight - self.previousTextHeight; // Update currently editing cell''s height CGRect editingCellFrame = self.editingCell.frame; editingCellFrame.size.height += difference; self.editingCell.frame = editingCellFrame; // Update UITableView contentSize self.contentSize = CGSizeMake(self.contentSize.width, self.contentSize.height + difference); // Scroll to bottom if cell is at the end of the table if (self.editingNoteInEndOfTable) { self.contentOffset = CGPointMake(self.contentOffset.x, self.contentOffset.y + difference); } else { // Update all next to editing cells NSInteger editingCellIndex = [self.visibleCells indexOfObject:self.editingCell]; for (NSInteger i = editingCellIndex; i < self.visibleCells.count; i++) { UITableViewCell *cell = self.visibleCells[i]; CGRect cellFrame = cell.frame; cellFrame.origin.y += difference; cell.frame = cellFrame; } } [self endUpdates]; } self.previousTextHeight = textHeight; }


Aquí hay una versión más corta de la respuesta de Simons para Swift 3. También permite alternar la selección de la celda

var cellIsSelected: IndexPath? func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { cellIsSelected = cellIsSelected == indexPath ? nil : indexPath tableView.beginUpdates() tableView.endUpdates() } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { if cellIsSelected == indexPath { return 250 } return 65 }


Compruebe este método después de iOS 7 y versiones posteriores.

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath{ return UITableViewAutomaticDimension; }

Se han realizado mejoras a esto en iOS 8. Podemos configurarlo como propiedad de la propia vista de tabla.


Encontré una solución REALMENTE SENCILLA a esto como un efecto secundario de un UITableView que estaba trabajando ...

Almacene la altura de la celda en una variable que informe la altura original normalmente a través de tableView: heightForRowAtIndexPath: luego, cuando desee animar un cambio de altura, simplemente cambie el valor de la variable y llame a esto ...

[tableView beginUpdates]; [tableView endUpdates];

Descubrirá que no hace una recarga completa, pero es suficiente para que UITableView sepa que tiene que volver a dibujar las celdas, capturando el nuevo valor de altura para la celda ... ¿y adivine qué? ANIMA el cambio por ti. Dulce.

Tengo una explicación más detallada y ejemplos de código completo en mi blog ... Animate UITableView Cell Height Change


Entradas -

tableView.beginUpdates () tableView.endUpdates () que estas funciones no llamarán

func tableView (_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {}

Pero, si lo hace, tableView.reloadRows (at: [selectedIndexPath! As IndexPath], con: .none)

Llamará a la función tableView (_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {} esta función.


Intenta esto es para expandir la fila indexwise:

@property (nonatomic) NSIndexPath *expandIndexPath; - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath { if ([indexPath isEqual:self.expandedIndexPath]) return 100; return 44; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSMutableArray *modifiedRows = [NSMutableArray array]; if ([indexPath isEqual:self.expandIndexPath]) { [modifiedRows addObject:self.expandIndexPath]; self.expandIndexPath = nil; } else { if (self.expandedIndexPath) [modifiedRows addObject:self.expandIndexPath]; self.expandIndexPath = indexPath; [modifiedRows addObject:indexPath]; } // This will animate updating the row sizes [tableView reloadRowsAtIndexPaths:modifiedRows withRowAnimation:UITableViewRowAnimationAutomatic]; // Preserve the deselection animation (if desired) [tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone]; [tableView deselectRowAtIndexPath:indexPath animated:YES]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ViewControllerCellReuseIdentifier]; cell.textLabel.text = [NSString stringWithFormat:@"I''m cell %ld:%ld", (long)indexPath.section, (long)indexPath.row]; return cell; }


Me gusta la respuesta de Simon Lee. Realmente no probé ese método pero parece que cambiaría el tamaño de todas las celdas de la lista. Esperaba un cambio de solo la celda que está girada. Lo hice como Simon, pero con solo una pequeña diferencia. Esto cambiará el aspecto de una celda cuando se seleccione. Y lo hace animar. Solo otra forma de hacerlo.

Cree un int para mantener un valor para el índice de celda seleccionado actual:

int currentSelection;

Entonces:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { int row = [indexPath row]; selectedNumber = row; [tableView beginUpdates]; [tableView endUpdates]; }

Entonces:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if ([indexPath row] == currentSelection) { return 80; } else return 40; }

Estoy seguro de que puedes hacer cambios similares en tableView: cellForRowAtIndexPath: para cambiar el tipo de celda o incluso cargar un archivo xib para la celda.

De esta manera, la selección actual comenzará en 0. Necesitaría realizar ajustes si no desea que la primera celda de la lista (en el índice 0) se vea seleccionada de forma predeterminada.


No sé qué es todo lo que se trata de llamar a beginUpdates / endUpdates en sucesión, solo puede usar -[UITableView reloadRowsAtIndexPaths:withAnimation:] . Aquí hay un proyecto de ejemplo .


Obtener la ruta de índice de la fila seleccionada. Recargar la mesa. En el método heightForRowAtIndexPath de UITableViewDelegate, establezca la altura de la fila seleccionada a una altura diferente y para las demás devuelva la altura de fila normal


Si es posible.

UITableView tiene un método delegado didSelectRowAtIndexPath

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [UIView animateWithDuration:.6 delay:0 usingSpringWithDamping:UIViewAnimationOptionBeginFromCurrentState initialSpringVelocity:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{ cellindex = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section]; NSArray* indexArray = [NSArray arrayWithObjects:indexPath, nil]; [violatedTableView beginUpdates]; [violatedTableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationAutomatic]; [violatedTableView endUpdates]; } completion:^(BOOL finished) { }]; }

Pero en su caso, si el usuario se desplaza y selecciona una celda diferente, debe tener la última celda seleccionada para reducir y expandir la celda actualmente seleccionada reloadRowsAtIndexPaths: llama a heightForRowAtIndexPath: así que maneje en consecuencia.


Usé la asombrosa respuesta de @ Joy, y funcionó perfectamente con ios 8.4 y XCode 7.1.1.

En el caso de que desee hacer que su celda se pueda cambiar, cambié el -tableViewDidSelect a lo siguiente:

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ //This is the bit I changed, so that if tapped once on the cell, //cell is expanded. If tapped again on the same cell, //cell is collapsed. if (self.currentSelection==indexPath.row) { self.currentSelection = -1; }else{ self.currentSelection = indexPath.row; } // animate [tableView beginUpdates]; [tableView endUpdates]; }

Espero que algo de esto te haya ayudado.


Versión rápida de la respuesta de Simon Lee :

tableView.beginUpdates() tableView.endUpdates()

Tenga en cuenta que debe modificar las propiedades de altura ANTES de endUpdates() .


Versión rápida de la respuesta de Simon Lee.

// MARK: - Variables var isCcBccSelected = false // To toggle Bcc. // MARK: UITableViewDelegate func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { // Hide the Bcc Text Field , until CC gets focused in didSelectRowAtIndexPath() if self.cellTypes[indexPath.row] == CellType.Bcc { if (isCcBccSelected) { return 44 } else { return 0 } } return 44.0 }

Luego en didSelectRowAtIndexPath ()

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { self.tableView.deselectRowAtIndexPath(indexPath, animated: true) // To Get the Focus of CC, so that we can expand Bcc if self.cellTypes[indexPath.row] == CellType.Cc { if let cell = tableView.cellForRowAtIndexPath(indexPath) as? RecipientTableViewCell { if cell.tag == 1 { cell.recipientTypeLabel.text = "Cc:" cell.recipientTextField.userInteractionEnabled = true cell.recipientTextField.becomeFirstResponder() isCcBccSelected = true tableView.beginUpdates() tableView.endUpdates() } } } }


reloadData no es bueno porque no hay animación ...

Esto es lo que estoy tratando actualmente:

NSArray* paths = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]]; [self.tableView beginUpdates]; [self.tableView insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationFade]; [self.tableView deleteRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationFade]; [self.tableView endUpdates];

Casi funciona bien. Casi. Estoy aumentando la altura de la celda, y algunas veces hay un pequeño "problema" en la vista de tabla cuando se reemplaza la celda, como si se estuviera preservando alguna posición de desplazamiento en la vista de tabla, la nueva celda (que es la primera celda) en la tabla) termina con su desplazamiento demasiado alto, y la vista de desplazamiento rebota para reposicionarla.


solo una nota para alguien como yo que busca agregar "Más detalles" en una celda personalizada.

[tableView beginUpdates]; [tableView endUpdates];

Hizo un excelente trabajo, pero no olvide "recortar" la vista de celda. Desde Interface Builder, seleccione su celda -> Vista de contenido -> desde Property Inspector, seleccione " subvista de clips "


reloadRowsAtIndexPaths con reloadRowsAtIndexPaths .

didSelectRowAtIndexPath en didSelectRowAtIndexPath la indexPath de la celda seleccionada y llamo reloadRowsAtIndexPaths al final (puede enviar NSMutableArray para obtener la lista de elementos que desea recargar).

En heightForRowAtIndexPath puede verificar si indexPath está en la lista o no de las celdas expandIndexPath y la altura de envío.

Puede consultar este ejemplo básico: https://github.com/ferminhg/iOS-Examples/tree/master/iOS-UITableView-Cell-Height-Change/celdascambiadetam Es una solución simple.

agrego un tipo de código si te ayudo

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 20; } -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath: (NSIndexPath*)indexPath { if ([indexPath isEqual:_expandIndexPath]) return 80; return 40; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Celda"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; [cell.textLabel setText:@"wopwop"]; return cell; } #pragma mark - #pragma mark Tableview Delegate Methods - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSMutableArray *modifiedRows = [NSMutableArray array]; // Deselect cell [tableView deselectRowAtIndexPath:indexPath animated:TRUE]; _expandIndexPath = indexPath; [modifiedRows addObject:indexPath]; // This will animate updating the row sizes [tableView reloadRowsAtIndexPaths:modifiedRows withRowAnimation:UITableViewRowAnimationAutomatic]; }


BOOL flag; - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { flag = !flag; [tableView beginUpdates]; [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; [tableView endUpdates]; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return YES == flag ? 20 : 40; }