¿Se puede animar un cambio de altura en una UITableViewCell cuando se selecciona?

votos
361

Estoy usando una UITableViewen 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 la interfaz de usuario para editar las propiedades de esa persona.

es posible?

Publicado el 20/01/2009 a las 04:17
fuente por usuario
En otros idiomas...                            


21 respuestas

votos
833

He encontrado una solución muy simple a esto como un efecto secundario a una UITableViewque estaba trabajando .....

Almacenar la altura de la celda en una variable que informa de la altura original, normalmente a través de tableView: heightForRowAtIndexPath:, a continuación, cuando se quiere animar un cambio de altura, basta con cambiar el valor de la variable y llamar a este ...

[tableView beginUpdates];
[tableView endUpdates];

Se dará cuenta de que no hace una recarga completa, pero es suficiente para que el UITableViewsaber tiene que volver a dibujar las células, agarrando el nuevo valor de la altura de la celda .... y adivina qué? Se anima el cambio para usted. Dulce.

Tengo más detalladas muestras de explicación y de código completo en mi blog ... Animate UITableView Alto de celda Cambio

Respondida el 14/01/2010 a las 12:42
fuente por usuario

votos
56

Me gusta la respuesta de Simon Lee. Yo en realidad no trato de ese método, pero parece que sería cambiar el tamaño de todas las celdas en la lista. Tenía la esperanza de un cambio de solo la célula que se toca. Yo un poco hice como Simón, pero con sólo una pequeña diferencia. Esto cambiará el aspecto de una célula cuando se selecciona. Y lo hace animado. Sólo otra manera de hacerlo.

Crear un int para contener un valor para el índice celda seleccionada 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 puede realizar cambios similares en tableView: cellForRowAtIndexPath: para cambiar el tipo de célula o incluso cargar un archivo xib para la célula.

Así, el currentSelection comenzará a 0. Usted tendría que hacer ajustes si no desea que la primera celda de la lista (con índice 0) a verse seleccionado por defecto.

Respondida el 26/04/2011 a las 00:25
fuente por usuario

votos
19

Añadir una propiedad para realizar un seguimiento de la celda seleccionada

@property (nonatomic) int currentSelection;

Se establece en un valor centinela en (por ejemplo) viewDidLoad, para asegurarse de que los UITableViewinicia en la posición 'normal'

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    //sentinel
    self.currentSelection = -1;
}

En heightForRowAtIndexPathpuede ajustar la altura que desea 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 didSelectRowAtIndexPathahorrarle la selección actual y guardar 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 didDeselectRowAtIndexPathestablecer el índice de selección de nuevo al valor centinela y animar la célula de nuevo a forma normal

- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {       
        // do things with your cell here

        // sentinel
        self.currentSelection = -1;

        // animate
        [tableView beginUpdates];
        [tableView endUpdates];
    }
}
Respondida el 05/08/2013 a las 17:02
fuente por usuario

votos
12

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

Esto es lo que estoy intentando en este momento:

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. Aumento la altura de la celda y, a veces, aparece un pequeño "hipo" en la vista de tabla cuando se reemplaza la celda, como si se conservara 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 reposicionarlo.

Respondida el 07/05/2009 a las 00:24
fuente por usuario

votos
10

Resolví con reloadRowsAtIndexPaths.

Ahorro en didSelectRowAtIndexPathel indexPath de celda seleccionada y llame reloadRowsAtIndexPathsal final (puedes enviar NSMutableArray para la lista de elemento de que desea volver a cargar).

En heightForRowAtIndexPathpuede comprobar si indexPath está en la lista o no de la celda de expandIndexPath y enviar altura.

Esto se puede comprobar ejemplo básico: https://github.com/ferminhg/iOS-Examples/tree/master/iOS-UITableView-Cell-Height-Change/celdascambiadetam Es una solución simple.

agrego una especie de código si ayudar

- (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];
}
Respondida el 14/11/2014 a las 13:20
fuente por usuario

votos
10

No sé lo que todas estas cosas de llamar beginUpdates / endUpdates en la serie es, sólo puede utilizar -[UITableView reloadRowsAtIndexPaths:withAnimation:]. He aquí un ejemplo de proyecto .

Respondida el 02/08/2014 a las 23:52
fuente por usuario

votos
2
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;
}
Respondida el 15/08/2016 a las 13:32
fuente por usuario

votos
2

Sólo una nota para alguien como yo en busca de agregar "Más detalles" en la celda personalizado.

[tableView beginUpdates];
[tableView endUpdates];

Hizo un excelente trabajo, pero no se olvide de vista celular "cultivo". De Interface Builder selecciona tu teléfono -> vista de contenido -> desde el inspector de propiedades, seleccione " subvista Clip "

Respondida el 25/03/2015 a las 20:08
fuente por usuario

votos
2

Prueba esto es para la expansión de 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;
}
Respondida el 24/09/2014 a las 06:41
fuente por usuario

votos
1

En lugar de beginUpdates()/ endUpdates(), la llamada recomendada es ahora:

tableView.performBatchUpdates(nil, completion: nil)

Apple dice que, con respecto beginUpdates / endUpdates: "Use los performBatchUpdates (_:. :) método de ejecución en lugar de éste siempre que sea posible"

Ver: https://developer.apple.com/documentation/uikit/uitableview/1614908-beginupdates

Respondida el 19/11/2018 a las 16:47
fuente por usuario

votos
1

Aquí está una versión más corta de Simons respuesta para Swift 3. También permite la conmutación de la selección de la célula

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
  }
Respondida el 30/05/2017 a las 20:36
fuente por usuario

votos
1

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()
            }
        }
    }
}
Respondida el 07/06/2016 a las 12:30
fuente por usuario

votos
0

Swift 4 y superiores

añadir a continuación el código en que el método fila delegado didselect de tableview

tableView.beginUpdates()
tableView.setNeedsLayout()
tableView.endUpdates()
Respondida el 23/11/2018 a las 11:53
fuente por usuario

votos
0

entradas -

tableView.beginUpdates () tableView.endUpdates () estas funciones no se llame

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

Pero, si lo hace, tableView.reloadRows (en: [selectedIndexPath como IndexPath!], Con: .none)

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

Respondida el 28/03/2018 a las 08:08
fuente por usuario

votos
0

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 endUpdates() .

Respondida el 08/02/2018 a las 11:11
fuente por usuario

votos
0

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, entonces u es necesario tener la última celda seleccionada para contraer o expandir la celda actualmente seleccionada reloadRowsAtIndexPaths:llamadas heightForRowAtIndexPath:lo que debe manipularse en consecuencia.

Respondida el 01/08/2016 a las 08:29
fuente por usuario

votos
0

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 establecer como propiedad de la propia vista de tabla.

Respondida el 04/03/2016 a las 09:10
fuente por usuario

votos
0

Solía ​​@ respuesta increíble de alegría, y funcionó a la perfección con iOS 8.4 y 7.1.1 XCode.

En caso de que usted está buscando para hacer su celular de palanca-poder, he cambiado 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 nada de esto le ayudó.

Respondida el 19/11/2015 a las 18:00
fuente por usuario

votos
0

Aquí está mi código de encargo UITableViewsubclase, que se expanden UITextViewen la celda de la tabla, sin necesidad de recargar (y perdió 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;
}
Respondida el 09/11/2015 a las 23:14
fuente por usuario

votos
-1

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, configuro isInEdit = YESy llamo al método [self onTimer]y anima el crecimiento de la celda hasta que alcanza el valor s_CellHeightEditing :-)

Respondida el 20/08/2009 a las 21:18
fuente por usuario

votos
-1

Obtenga 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 los demás devuelva la altura de fila normal

Respondida el 21/01/2009 a las 16:13
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more