2010-06-17 7 views
56

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 Funktionsweise 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.Akkordeon-Tabelle Zelle - Wie dynamisch expandit/contract uitableviewcell?

Wenn Sie sich die Digg-App und andere, die dies getan haben, sehen, 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 mit neha Methode unten gemacht und während die Zelle die richtige Art und Weise Animieren es Chaos mit den anderen Zellen in der Tabelle anzurichten. Was ich getan habe, ist subclassed UITableViewCell mit einer benutzerdefinierten Klasse, 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 Delegatmethoden 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 nun, dass die Zelle erweitert, aber nicht tatsächlich aktualisiert werden, so dass die Etiketten und Textfeld Arent gezeigt wird. Sie erscheinen jedoch, wenn ich die Zelle ab und auf dem Bildschirm scrolle.

Irgendwelche Ideen?

+0

jemand ändern? Sie suchen keinen detaillierten Code, sondern nur einige Richtlinien, wie Sie dies erreichen können? –

+0

Warum machst du Pawels Antwort nicht die richtige Antwort ... Du kannst nicht besser werden. –

Antwort

2

Erstellen Sie eine Klasse, die UITableviewcell in Ihrem Projekt unterklassifiziert. Erstellen Sie diese Klasse Feder und legen Sie seine Eltern die Klasse in Ihrem Projekt mit Tableview zu sein und außer Kraft setzen seine -

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

Schreibmethoden contractCell() und expandCell() in dieser Klasse und stellen die Höhe der Zellen, die Sie Will in ExpandCell-Methode. 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 für die Zellenauswahl die Methode Ihrer Tabellenansicht.

+0

neha, thx für Ihre Antwort. Könnten Sie ein wenig darauf eingehen, wie genau das geht? Bin ich noch ein wenig verwirrt darüber, wie man die setSelected: Methode benutzt? Wird die tableCell die Höhe nach dem Aufruf von expandCell/contractCell automatisch anpassen und, was noch wichtiger ist, erscheint es so, als ob die ausgewählte Zelle expandiert und nicht einfach neu geladen wird. Ich rief reoloadRowsAtIndex in didSelectRowAtIndex an und während das funktionierte, konnte man die Zelle, die neu geladen wurde, entweder von oben/unten/etc sehen. abhängig vom gewählten Animationsstil. –

+0

Sobald Sie eine Klasse erstellen, die uitablviewcell Unterklassen, die Methode "(void) setSelected: (BOOL) ausgewählt animiert: (BOOL) animiert" automatisch in der erstellten Klasse erscheint, die explizit aufgerufen wird, wenn Sie eine Zelle in der Tabellenansicht auswählen. Es ist zum Konfigurieren der Ansicht für den ausgewählten Zustand der Zelle gedacht. Stellen Sie sicher, dass Sie auch eine Schreibmarke dieser Unterklasse "uitableviewcell" erstellen, und legen Sie das übergeordnete Element dieser Schreibfeder als die Klasse Ihrer Tabellenansicht fest. Ja, das wird Ihnen den Effekt geben, den Sie erwarten, es wird zeigen, dass sich die Zellen ausdehnen/zusammenziehen und nicht nachladen. – neha

+0

hi neha, thx nochmal zum antworten. Ich scheine jedoch einige Fortschritte zu machen, siehe oben, für Veränderungen, die ich versucht habe und Probleme, die ich noch habe. Auch welcher Code sollte genau in die setSelected: Methode gehen? Ich versuche immer noch, durch dieses leider zu stolpern. thx –

92

Die Apple-Art zu tun 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 beginnen erklären werde/Ende aktualisiert späteren Teil.

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

Dies wird Höhe 100 für die ausgewählte Zelle zurückgeben.

Jetzt können wir zu den Start-/End-Updates zurückkehren. Dieser Block löst 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.

Hoffnung, das war hilfreich, Pawel

+0

Hallo Pawel, habe das probiert und der Animationseffekt ist genau das wonach ich suche aber das Thema Ich lief darin ist, dass dieser Code cellForRowAtIndex nicht anruft, also konnte ich nicht herausfinden, wie/wo man den Inhalt der ausgedehnten Zelle ändert. Es passt einfach die Höhe der Zelle an. Ich versuchte auch, die Zelle in didSelectRowAtIndex mit zu erhalten: UITableViewCell * cell = [tableView cellForRowAtIndexPath: indexPath]; und Änderungen an der Zelle vornehmen und dann beginUpdates aufrufen. Während dies funktioniert, scheint es den Rest des Tisches zu verheeren. Können Sie erklären, wo Sie Änderungen an der ausgewählten Zelle vornehmen, um dies zu vermeiden? –

+5

Da Sie die Start-/Endaktualisierungen in der Methode didSelectCellForRowAtIndexPath: aufrufen, wurde die Zelle bereits ausgewählt. Daher können Sie die setSelected: animated: -Methode in Ihrer Zellenimplementierung verwenden, um sie für den ausgewählten Status zu konfigurieren. – Pawel

+0

Hallo, ich habe meinen obigen Code aktualisiert, um einige dieser Änderungen widerzuspiegeln, aber es scheint, dass wenn ich den Code zum Erstellen des neuen Inhalts wie Labels, Textfelder usw. in die cellForRowAtIndex-Methode einfüge, dann nicht funktioniert, weil diese Methode nicht aufgerufen wird Sie rufen [tableView beginUpdate] und [tableView endUpdates] auf. Also bin ich mir nicht sicher, wo ich diesen Code ablegen soll und wie ich die setSelected: -Methode richtig einsetzen kann? Jeder Ratschlag macht mich verrückt. –

0

Ersetzen Sie Ihre cellForRowAtIndexPath Funktion mit diesem.

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

Pawels beginUpdates/EndUpdates Trick ist gut, und ich verwende es 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 komplette Arbeits Umsetzung dessen, was ich denke, Sie versuchen zu erreichen:

.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 

Wenn Sie nicht tun möchte die Zelle neu laden (du willst deine bestehende Zelle behalten und nur die Größe ändern, und wahrscheinlich einige Subviews hinzufügen oder entfernen), dann mach einfach den beginUpdates/endUpdates Trick in didSelectRowAtIndexPath: und rufe so auf Me-Methode auf Ihrer Zelle, um die Layoutänderung anzuregen. 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.

-1

Array wof Wörterbuch erstellen, die eine Schlüssel Select_sts haben, die 0 in Start ist, wenn seine Änderung 1 klicken accourding u Tabelle

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

} 
Verwandte Themen