2010-06-17 6 views
56

J'essaye de créer un uitableviewcell de type accordéon qui, lorsque l'utilisateur sélectionne la cellule, l'agrandit pour afficher une vue détaillée en ligne similaire à celle de l'application digg. J'ai d'abord essayé de remplacer le tablecell actuel avec une cellule personnalisée dans cellForRowAtIndex mais l'animation semble un peu saccadée car vous pouvez voir la cellule en cours de remplacement et globalement l'effet ne fonctionne pas bien.Cellule de table d'accordéon - Comment agrandir/contracter dynamiquement uitableviewcell?

Si vous regardez l'application digg et d'autres qui ont fait cela, il semble qu'ils ne remplacent pas la cellule actuelle, mais plutôt en ajoutant peut-être une sous-vue à la cellule? La cellule d'origine ne semble cependant pas animer du tout et seule la nouvelle vue s'accorde dans la table.

Est-ce que quelqu'un a des idées pour accomplir un effet similaire?

Mise à jour: J'ai fait quelques progrès en utilisant la méthode de Neha ci-dessous et alors que la cellule est Animer le bon sens, il est en train de causer des ravages avec les autres cellules du tableau. Ce que j'ai fait est sous-classé UITableViewCell avec une classe personnalisée qui contient une instance d'un UIView qui dessine réellement la vue que j'ajoute ensuite au contenu de la table.

- (void)setSelected:(BOOL)selected animated:(BOOL)animated { 

if (selected) { 
    [self expandCell]; 
} 
} 

-(void)expandCell { 
    self.contentView.frame = CGRectMake(0.0, 0.0, self.contentView.bounds.size.width, 110); 
} 

Voici toutes les tables méthodes de délégués: J'UTILISE

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 

if (isSearching && indexPath.row == selectedIndex) { 

    static NSString *CellIdentifier = @"SearchCell"; 
    CustomTableCell *cell = (CustomTableCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if (cell == nil) { 
     cell = [[[CustomTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 
    } 

    [cell setCustomTitle:[timeZoneNames objectAtIndex:indexPath.row] detail:[timeZoneNames objectAtIndex:indexPath.row]]; 

    UILabel *theText = [[UILabel alloc] initWithFrame:CGRectMake(10.0, 10.0, cell.contentView.bounds.size.width -20, 22.0)]; 
    theText.text = @"Title Text"; 
    [cell.contentView addSubview:theText]; 


    UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(10.0, 10 + 46.0, cell.contentView.bounds.size.width - 20, 40.0)]; 
    textField.borderStyle = UITextBorderStyleLine; 
    [cell.contentView addSubview:textField];   

    UILabel *testLabel = [[UILabel alloc] initWithFrame:CGRectMake(5.0, 88.0, cell.contentView.bounds.size.width - 20, 22.0)]; 
    testLabel.text = [NSString stringWithFormat:@"Some text here"]; 
    [cell.contentView addSubview:testLabel]; 

    [theText release]; 
    [textField release]; 
    [testLabel release]; 

    return cell;   
} else { 

    static NSString *CellIdentifier = @"Cell"; 
    CustomTableCell *cell = (CustomTableCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if (cell == nil) { 
     cell = [[[CustomTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 
    } 

    [cell setCustomTitle:[timeZoneNames objectAtIndex:indexPath.row] detail:[timeZoneNames objectAtIndex:indexPath.row]]; 
    return cell; 
} 


- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 

[tableView deselectRowAtIndexPath:indexPath animated:NO]; 

selectedIndex = indexPath.row; 
isSearching = YES; 


[tableView beginUpdates]; 
[tableView endUpdates]; 

} 


- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {   
if (isSearching && indexPath.row == selectedIndex) { 
    return 110; 
} 
return rowHeight;   
} 

Il semble maintenant que la cellule est en pleine expansion, mais pas réellement rafraîchi de sorte que les étiquettes et textfield ne coûtent pas être représentés. Ils apparaissent cependant quand je fais défiler la cellule et sur l'écran.

Des idées?

+0

quelqu'un? Vous ne cherchez pas de code détaillé, mais plutôt quelques lignes directrices sur la façon d'y parvenir? –

+0

Pourquoi ne faites-vous pas répondre à la bonne réponse de Pawel ... Vous ne pouvez pas aller mieux que ça. –

Répondre

2

Créez une classe qui sous-classe UITableviewcell dans votre projet. Créer cette pointe de classe et définir sa mère d'être la classe dans votre projet avec tableview et passer outre ses -

(void)setSelected:(BOOL)selected animated:(BOOL)animated 

Méthodes d'écriture contractCell() et expandCell() dans cette classe, et de fournir la hauteur des cellules que vous vouloir dans la méthode expandCell. Appelez ces méthodes de manière appropriée en fonction de certains indicateurs définis pour identifier si la cellule est dans un état étendu ou contracté. Utilisez votre tableview

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 

méthode pour gérer la sélection des cellules.

+0

neha, merci pour votre réponse. Pourriez-vous élaborer un peu sur la façon exacte de procéder? Im encore un peu confus sur la façon d'utiliser la méthode setSelected:? La tableCell ajustera-t-elle automatiquement la hauteur après l'appel de expandCell/contractCell et, plus important encore, apparaîtra-t-elle comme si la cellule sélectionnée était en expansion et n'était pas simplement rechargée, ce qui est le problème initial? J'ai appelé reoloadRowsAtIndex dans didSelectRowAtIndex et pendant que cela fonctionnait, vous pouviez voir visuellement la cellule en train d'être rechargée, depuis le haut/bas/etc. en fonction du style d'animation choisi. –

+0

Une fois que vous créez une classe qui sous-classe uitablviewcell, la méthode "(void) setSelected: (BOOL) sélectionnée animée: (BOOL) animée" apparaît automatiquement dans la classe créée explicitement appelée chaque fois que vous sélectionnez une cellule dans tableview. Il est destiné à configurer la vue pour l'état de cellule sélectionné. Assurez-vous de créer également une plume de cette sous-classe uitableviewcell et définissez le parent de cette plume comme classe de votre tableview. Oui, cela vous donnera l'effet que vous attendez, il montrera les cellules en expansion/contracter et ne pas recharger. – neha

+0

salut neha, merci encore pour répondre. J'ai l'air de faire quelques progrès cependant pls voir ci-dessus pour les changements que j'ai essayés et les problèmes que j'ai toujours. Aussi quel code devrait exactement aller dans la méthode setSelected:? Toujours essayer de trébucher à travers cela malheureusement. thx –

92

La manière d'Apple à faire est assez simple.

Tout d'abord, vous devez enregistrer la ligne de indexPath sélectionné:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 
    self.selectedRowIndex = [indexPath retain]; 
    [tableView beginUpdates]; 
    [tableView endUpdates]; 
} 

Je vais vous expliquer le début/fin une partie mise à jour plus tard. Puis, lorsque vous avez l'index actuellement sélectionné, vous pouvez indiquer à tableView qu'il doit donner plus d'espace à cette ligne.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 
    //check if the index actually exists 
    if(selectedRowIndex && indexPath.row == selectedRowIndex.row) { 
     return 100; 
    } 
    return 44; 
} 

Cela retournera la hauteur 100 pour la cellule sélectionnée.

Maintenant, nous pouvons revenir aux mises à jour de début/fin. Ce bloc déclenche le rechargement de toute la géométrie tableView.De plus, ce bloc est animé, ce qui donne finalement les impressions de la ligne en expansion.

Hope this utile, Pawel

+0

Salut Pawel, essayé ceci et l'effet d'animation est exactement ce que je cherche mais le problème Je suis tombé sur est que ce code n'appelle pas cellForRowAtIndex donc je ne pouvais pas comprendre comment/où modifier le contenu de la cellule étendue. Il ajuste simplement la hauteur de la cellule. J'ai également essayé d'obtenir la cellule dans didSelectRowAtIndex avec: UITableViewCell * cell = [tableView cellForRowAtIndexPath: indexPath]; et apportez des modifications à la cellule, puis appelez beginUpdates. Bien que cela fonctionne, il semble faire des ravages sur le reste de la table. Pouvez-vous expliquer où vous apportez des modifications à la cellule sélectionnée pour éviter cela? –

+5

Puisque vous appelez les mises à jour de début/fin dans la méthode didSelectCellForRowAtIndexPath:, la cellule a déjà été sélectionnée. Vous pouvez donc utiliser la méthode setSelected: animated: dans votre implémentation de cellule pour la configurer pour l'état sélectionné. – Pawel

+0

Salut, j'ai mis à jour mon code pour refléter certains de ces changements mais il semble que si je mets le code pour créer le nouveau contenu tel que labels, textfields, etc. dans la méthode cellForRowAtIndex, ça ne marche pas parce que cette méthode n'est pas appelée vous appelez [tableView beginUpdate] & [tableView endUpdates]. Donc, je ne suis pas sûr où placer ce code et comment utiliser correctement la méthode setSelected:? Tout conseil cela me rend fou. –

0

Remplacez votre fonction cellForRowAtIndexPath avec celui-ci.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath 
*)indexPath { 

    if (isSearching && indexPath.row == selectedIndex) { 

     static NSString *CellIdentifier = @"SearchCell"; 
     CustomTableCell *cell = [[[CustomTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 

     [cell setCustomTitle:[timeZoneNames objectAtIndex:indexPath.row] detail:[timeZoneNames objectAtIndex:indexPath.row]]; 

     UILabel *theText = [[UILabel alloc] initWithFrame:CGRectMake(10.0, 
10.0, cell.contentView.bounds.size.width 
-20, 22.0)]; 
     theText.text = @"Title Text"; 
     [cell.contentView addSubview:theText]; 


     UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(10.0, 10 + 
46.0, cell.contentView.bounds.size.width - 20, 40.0)]; 
     textField.borderStyle = UITextBorderStyleLine; 
     [cell.contentView addSubview:textField];   

     UILabel *testLabel = [[UILabel alloc] initWithFrame:CGRectMake(5.0, 
88.0, cell.contentView.bounds.size.width - 20, 22.0)]; 
     testLabel.text = [NSString stringWithFormat:@"Some text here"]; 
     [cell.contentView addSubview:testLabel]; 

     [theText release]; 
     [textField release]; 
     [testLabel release]; 

     return cell;   
    } else { 

     static NSString *CellIdentifier = @"Cell"; 
     CustomTableCell *cell = [[[CustomTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 

     [cell setCustomTitle:[timeZoneNames objectAtIndex:indexPath.row] detail:[timeZoneNames objectAtIndex:indexPath.row]]; 
     return cell; 
    } 
    } 
5

Le truc beginUpdates/endUpdates de Pawel est bon, et je l'utilise souvent. Mais dans ce cas, vous devez simplement recharger les lignes qui changent d'état, en vous assurant que vous les rechargez correctement avec le type de cellule désiré, et que vous retournez la nouvelle hauteur de cellule correcte.

Voici une implémentation complète de travail de ce que je pense que vous essayez d'accomplir:

.h:

#import <UIKit/UIKit.h> 

@interface ExpandingTableViewController : UITableViewController 
{ 

} 

@property (retain) NSIndexPath* selectedIndexPath; 

@end 

.m:

@implementation ExpandingTableViewController 
@synthesize selectedIndexPath; 

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 
    // Return the number of sections. 
    return 1; 
} 


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    // Return the number of rows in the section. 
    return 10; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 

    static NSString *CellIdentifier1 = @"Cell1"; 
    static NSString *CellIdentifier2 = @"Cell2"; 

    UITableViewCell *cell; 

    NSIndexPath* indexPathSelected = self.selectedIndexPath; 

    if (nil == indexPathSelected || [indexPathSelected compare: indexPath] != NSOrderedSame) 
    { 
     cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1]; 
     if (cell == nil) { 
      cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier1] autorelease]; 
     } 

     cell.textLabel.text = [NSString stringWithFormat: @"cell %d", indexPath.row]; 
    } 
    else 
    { 
     cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2]; 
     if (cell == nil) { 
      cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier2] autorelease]; 
     } 

     cell.textLabel.text = [NSString stringWithFormat: @"cell %d", indexPath.row]; 
     cell.detailTextLabel.text = [NSString stringWithFormat: @"(expanded!)", indexPath.row]; 
    } 

    return cell; 
} 

#pragma mark - 
#pragma mark Table view delegate 

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    if (self.selectedIndexPath != nil && [self.selectedIndexPath compare: indexPath] == NSOrderedSame) 
    { 
     return tableView.rowHeight * 2; 
    } 

    return tableView.rowHeight; 
} 

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    NSArray* toReload = [NSArray arrayWithObjects: indexPath, self.selectedIndexPath, nil]; 
    self.selectedIndexPath = indexPath; 

    [tableView reloadRowsAtIndexPaths: toReload withRowAnimation: UITableViewRowAnimationMiddle]; 
} 


#pragma mark - 
#pragma mark Memory management 

- (void)didReceiveMemoryWarning { 
    [super didReceiveMemoryWarning]; 
} 

- (void)viewDidUnload { 
} 

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

@end 

Si vous n'êtes pas vous voulez recharger la cellule (vous voulez conserver votre cellule existante et juste changer la taille, et probablement ajouter/supprimer des sous-vues), alors faites simplement l'astuce beginUpdates/endUpdates dans didSelectRowAtIndexPath :, et appelez ainsi me méthode sur votre cellule pour inciter le changement de mise en page. beginUpdates/endUpdates invite la tableView à re-interroger les hauteurs de chaque cellule - assurez-vous de retourner la bonne valeur.

-1

créer une matrice de dictionnaire wof qui ont une Select_sts clé qui est 0 en début quand cliquez sur le changement 1 accourding u table à langer

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{ 

    customView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 40.0)]; 
    UILabel * headerLabel = [[UILabel alloc] initWithFrame:CGRectZero]; 
    headerLabel.backgroundColor = [UIColor clearColor]; 
    headerLabel.opaque = NO; 
    headerLabel.textColor = [UIColor blackColor]; 
    headerLabel.highlightedTextColor = [UIColor whiteColor]; 
    headerLabel.font = [UIFont boldSystemFontOfSize:16]; 
    headerLabel.frame = CGRectMake(5.0, 10.0, 300.0, 20.0); 
    headerLabel.text=[NSString stringWithFormat: @"PNR %@",[[record objectAtIndex:section] objectForKey:@"number"]]; 
    customView.backgroundColor=[UIColor whiteColor]; 

btn_openClose.tag=section+10000; 
    btn_openClose.backgroundColor=[UIColor clearColor]; 
    // [btn_openClose setImage:[UIImage imageNamed:@"down_arrow.png"] forState:UIControlStateNormal]; 
    [btn_openClose addTarget:self action:@selector(collapseExpandButtonTap:) forControlEvents:UIControlEventTouchUpInside]; 
    [customView addSubview:btn_openClose]; 

} 


- (void) collapseExpandButtonTap:(id) sender{ 
    int indexNo=[sender tag]-10000; 
// NSLog(@"total_record %@",[total_record objectAtIndex:indexNo]); 
    NSMutableDictionary *mutDictionary = [[total_record objectAtIndex:indexNo] mutableCopy]; 
    if([[mutDictionary objectForKey:@"Select_sts"] integerValue]==0) 
     [mutDictionary setObject:[NSNumber numberWithInt:1] forKey:@"√"]; 
    else 
     [mutDictionary setObject:[NSNumber numberWithInt:0] forKey:@"Select_sts"]; 

    [total_record replaceObjectAtIndex:indexNo withObject:mutDictionary]; 

// [table_view beginUpdates]; 
// [table_view reloadData]; 
// [table_view endUpdates]; 

    NSMutableIndexSet *indetsetToUpdate = [[NSMutableIndexSet alloc]init]; 
    [indetsetToUpdate addIndex:indexNo]; // [indetsetToUpdate addIndex:<#(NSUInteger)#>] 
    // You can add multiple indexes(sections) here. 
    [table_view reloadSections:indetsetToUpdate withRowAnimation:UITableViewRowAnimationFade]; 

} 
Questions connexes