web-dev-qa-db-fra.com

Existe-t-il un moyen d'actualiser la hauteur des cellules sans recharger / recharger la ligne?

Je crée une vue comme iMessage, il suffit de saisir du texte dans la vue de texte inférieure. J'utilise la vue tabulaire pour ce faire, et la vue texte dans la dernière cellule. lorsque je saisis du texte long sur plusieurs lignes, j'ai besoin que la vue texte et la cellule deviennent plus personnalisées. j'ai donc besoin de rafraîchir la hauteur de la cellule. mais si j'utilise le rechargement de la vue tabulaire ou la ligne de rechargement, le contenu en mode texte disparaîtra et le clavier disparaîtra également. Y a-t-il un meilleur moyen de le réparer?

Peut-être devrais-je utiliser la barre d'outils pour le faire facilement? mais je doute toujours que la vue de table puisse le faire.

26
ZhouQi

Les cellules seront redimensionnées en douceur lorsque vous appelez beginUpdates et endUpdates. Après ces appels, la tableView enverra tableView:heightForRowAtIndexPath: pour toutes les cellules du tableau, lorsque tableView a obtenu toutes les hauteurs pour toutes les cellules, il animera le redimensionnement.

Et vous pouvez mettre à jour les cellules sans les recharger en définissant directement les propriétés de la cellule. Il n'est pas nécessaire d'impliquer la tableView et tableView:cellForRowAtIndexPath:

Pour redimensionner les cellules, vous utiliseriez un code similaire à celui-ci

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    NSString *newText = [textView.text stringByReplacingCharactersInRange:range withString:text];
    CGSize size = // calculate size of new text
    if ((NSInteger)size.height != (NSInteger)[self tableView:nil heightForRowAtIndexPath:nil]) {
        // if new size is different to old size resize cells. 
        // since beginUpdate/endUpdates calls tableView:heightForRowAtIndexPath: for all cells in the table this should only be done when really necessary.
        [self.tableView beginUpdates];
        [self.tableView endUpdates];
    }
    return YES;
}

pour changer le contenu d'une cellule sans recharger j'utilise quelque chose comme ceci:

- (void)configureCell:(FancyCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    MyFancyObject *object = ...
    cell.textView.text = object.text;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    FancyCell *cell = (FancyCell *)[tableView dequeueReusableCellWithIdentifier:@"CellWithTextView"];
    [self configureCell:cell forRowAtIndexPath:indexPath];
    return cell;
}

// whenever you want to change the cell content use something like this:

    NSIndexPath *indexPath = ...
    FancyCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
    [self configureCell:cell forRowAtIndexPath:indexPath];
67
Matthias Bauch

J'ai écrit une sous-classe de UITableViewCell pour gérer cette fonctionnalité.

Fichier .h:

#import <UIKit/UIKit.h>

@protocol AECELLSizeableDelegate;

@interface AECELLSizeable : UITableViewCell

@property (weak, nonatomic) id <AECELLSizeableDelegate> delegate;

@property IBOutlet UIView *viewMinimized;
@property IBOutlet UIView *viewMaximized;
@property BOOL maximized;

@property CGFloat height;

- (IBAction)clickedConfirm:(id)sender;
- (IBAction)clickedCancel:(id)sender;

- (void)minimizeForTableview: (UITableView*)tableView;
- (void)maximizeForTableview: (UITableView*)tableView;
- (void)toggleForTableview: (UITableView*)tableView;

@end

@protocol AECELLSizeableDelegate <NSObject>

- (void)sizeableCellConfirmedForCell: (AECELLSizeable*)cell;
- (void)sizeableCellCancelledForCell: (AECELLSizeable*)cell;

@end

Fichier .m:

#import "AECELLSizeable.h"

@implementation AECELLSizeable

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Initialization code
    }
    return self;
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

- (void)minimizeForTableview: (UITableView*)tableView
{
    self.maximized = NO;
    [self.viewMinimized setHidden:NO];
    [self.viewMaximized setHidden:YES];
    self.height = self.viewMinimized.frame.size.height;
    [tableView beginUpdates];
    [tableView endUpdates];
}

- (void)maximizeForTableview: (UITableView*)tableView
{
    self.maximized = YES;
    [self.viewMinimized setHidden:YES];
    [self.viewMaximized setHidden:NO];
    self.height = self.viewMaximized.frame.size.height;
    [tableView beginUpdates];
    [tableView endUpdates];
}

- (void)toggleForTableview:(UITableView *)tableView
{
    if (self.maximized) {
        [self minimizeForTableview:tableView];
    } else {
        [self maximizeForTableview:tableView];
    }
}

- (void)clickedConfirm:(id)sender
{
    [self.delegate sizeableCellConfirmedForCell:self];
}

- (void)clickedCancel:(id)sender
{
    [self.delegate sizeableCellCancelledForCell:self];
}

@end

Exemple d'utilisation:

  1. Créer un UITableViewController avec un UITableView statique dans IB
  2. Ajouter une cellule à la vue de table qui est un AECELLSizeable (ou une sous-classe de celle-ci)
  3. Créez deux UIViews dans cette cellule. Un UIView sera utilisé pour le contenu visible tout en étant réduit, l'autre sera utilisé pour le contenu visible en étant agrandi. Assurez-vous que ces cellules commencent à 0 sur l'axe y et que leur hauteur est égale à celle de la hauteur que vous souhaitez avoir la cellule pour chaque état.
  4. Ajoutez les sous-vues que vous souhaitez à ces deux vues. Ajoutez éventuellement la confirmation et l'annulation des boutons UIB à la vue UIV maximisée et connectez les IBActions fournies pour recevoir des rappels de délégués sur ces événements.
  5. Définissez votre contrôleur de table pour qu'il soit conforme à AECELLSizeableDelegate et définissez la propriété déléguée de la cellule sur le contrôleur de table.
  6. Créez un IBOutlet dans votre fichier d'interface UIViewController pour la cellule AECELLSizeable.
  7. De retour dans IB, assurez-vous que la hauteur initiale de la cellule est celle de la version réduite et connectez l'IBOutlet que vous venez de créer.
  8. Définissez la méthode de rappel heightForRowAtIndexPath de tableview dans le fichier d'implémentation du contrôleur tableview en tant que telle:

    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
      {
          if (indexPath.row == 0) {
              //Sizeable Cell
              return self.cellSizeable.height;
          } else {
              return [super tableView:tableView heightForRowAtIndexPath:indexPath];
          }
      }
    
  9. Dans la méthode viewDidLoad de votre contrôleur tableview, appelez minimForTableview sur votre cellule pour vous assurer qu'elle démarre au minimum.

  10. Ensuite, appelez maximiserForTableview: sur la cellule lorsqu'elle est sélectionnée via le rappel didSelectRowAtIndexPath à partir de la table (ou de toute autre manière que vous souhaitez gérer) et appelez la méthode minimForTableview: sur la cellule lorsque vous recevez les rappels délégués annulés/confirmés du (ou, encore une fois, mais vous souhaitez le gérer).
2
Adam Eisfeld