Akkordeon-Tabellenzelle – Wie kann man uitableviewcell dynamisch erweitern / verkleinern?

Ich versuche, einen Akkordeon-Typ von uitableviewcell zu erstellen, der, wenn der Benutzer die Zelle auswählt, so erweitert wird, dass eine detaillierte Infoansicht ähnlich der functionsweise der digg-App angezeigt wird. Ich habe anfangs versucht, die aktuelle Tabellenzelle durch eine benutzerdefinierte Zelle in cellForRowAtIndex zu ersetzen, aber die Animation sieht etwas abgehackt aus, da man sehen kann, dass die Zelle ersetzt wurde und der Effekt insgesamt nicht gut funktioniert.

Wenn Sie sich die Digg-App und andere, die dies getan haben, ansehen, scheint es, dass sie die aktuelle Zelle nicht ersetzen, sondern vielleicht eine Unteransicht der Zelle hinzufügen? Die ursprüngliche Zelle scheint jedoch überhaupt nicht zu animieren und nur die neue Ansicht akkordeoniert in die Tabelle.

Hat jemand irgendwelche Ideen, wie man einen ähnlichen Effekt erzielt?

Update: Ich habe einige Fortschritte gemacht, indem ich nehas Methode weiter unten benutze und während die Zelle den richtigen Weg animiert, verwüstet sie mit den anderen Zellen in der Tabelle. Was ich getan habe, ist subclassed UITableViewCell mit einer benutzerdefinierten class, die eine Instanz einer UIView enthält, die tatsächlich die Ansicht zeichnet, die ich dann der Inhaltsansicht der Tabellenzellen hinzufüge.

- (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); } 

Hier sind alle Tabellen Delegate Methoden, die ich verwende:

 - (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; } 

Es scheint jetzt, dass die Zelle erweitert wird, aber nicht wirklich aktualisiert wird, so dass die Etiketten und das Textfeld nicht gezeigt werden. Sie erscheinen jedoch, wenn ich die Zelle ab und auf dem Bildschirm scrolle.

Irgendwelche Ideen?

Der Apple-Weg ist ziemlich einfach.

Zuerst müssen Sie die ausgewählte indexPath-Zeile speichern:

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

Ich werde den Anfang / Ende aktualisierten Teil später erklären.

Wenn Sie den aktuell ausgewählten Index haben, können Sie der tableView mitteilen, dass dieser Zeile mehr Speicherplatz zugewiesen werden soll.

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

Dadurch wird die Höhe 100 für die ausgewählte Zelle zurückgegeben.

Jetzt können wir zu den Start- / End-Updates zurückkehren. Dieser Block triggers das erneute Laden aller TableView-Geometrie aus. Außerdem ist dieser Block animiert, was schließlich dazu führt, dass sich die Impressions der Reihe erweitern.

Hoffe, das war hilfreich, Pawel

Pawel’s beginUpdates / endUpdates Trick ist gut und ich benutze ihn oft. In diesem Fall müssen Sie jedoch einfach die Zeilen, die den Status ändern, erneut laden, um sicherzustellen, dass Sie sie mit dem gewünschten Zelltyp korrekt neu laden, und dass Sie die korrekte neue Zellenhöhe zurückgeben.

Hier ist eine vollständige Arbeitsimplementierung dessen, was ich zu erreichen versuche:

.h:

 #import  @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 

Wenn Sie die Zelle nicht erneut laden möchten (Sie möchten Ihre vorhandene Zelle behalten und nur die Größe ändern und wahrscheinlich einige Unteransichten hinzufügen oder entfernen), führen Sie einfach den Trick beginUpdates / endUpdates in didSelectRowAtIndexPath: aus und rufen Sie eine Methode auf Ihre Zelle, um das Layout zu ändern. beginUpdates / endUpdates fordert die tableView auf, die Höhen für jede Zelle erneut abzufragen – stellen Sie also sicher, dass Sie den korrekten Wert zurückgeben.

Erstellen Sie eine class, die UITableviewcell in Ihrem Projekt unterklassifiziert. Erstellen Sie die class dieser class und legen Sie ihr übergeordnetes Objekt als class in Ihrem Projekt mit tableview fest und überschreiben Sie es.

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

Schreiben Sie in dieser class die Methoden contractCell () und expandCell (), und geben Sie in der Methode expandCell die Höhe der gewünschten Zellen an. Rufen Sie diese Methoden entsprechend auf, indem Sie einige Flags setzen, um festzustellen, ob sich die Zelle im erweiterten Zustand oder im kontrahierten Zustand befindet. Verwenden Sie Ihre Tabellenansicht

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

Methode zur Auswahl von Zellen.

Ersetzen Sie die function cellForRowAtIndexPath durch diese function.

  - (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; } } 

Erstellen Sie Array-Worf-Wörterbücher, die einen Schlüssel Select_sts haben, der 0 in Start ist, wenn Sie auf seine Change-1-Accourding-u-Change-Tabelle klicken

 - (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]; }