手风琴表格单元格 – 如何dynamic展开/收缩uitableviewcell?

我正在尝试创build一个手风琴types的uitableviewcell,当用户select单元格时,它展开显示一个类似于digg应用程序的内联详细信息视图。 我最初尝试用cellForRowAtIndex中的customcellreplace当前的tablecell,但是animation看起来有点不连贯,因为您可以看到被replace的单元格,总的来说效果不太好。

如果你看看digg应用程序和其他谁已经这样做,似乎他们并没有取代当前的单元格,而是可能添加一个子视图到单元格? 然而,原来的细胞似乎根本没有animation,只有新的观点进入表格。

有没有人有任何想法如何实现类似的效果?

更新:我使用下面的neha的方法取得了一些进展,而单元格正在animation正确的方式是破坏表中的其他单元格的破坏。 我所做的是UITableViewCell与一个自定义类,其中包含一个UIView的实例,它实际上绘制视图,然后添加到表单元格contentview的子视图。

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

这里是我使用的所有表代表方法:

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

现在看起来单元格正在扩展,但实际上并没有被刷新,因此标签和文本字段不被显示。 但是,当我滚动单元格和屏幕时,他们会显示出来。

有任何想法吗?

苹果的方法很简单。

首先,您需要保存选定的indexPath行:

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

稍后我会解释开始/结束更新的部分。

然后,当你有当前select的索引,你可以告诉tableView它应该给这一行更多的空间。

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

这将返回所选单元格的高度100。

现在我们可以回到开始/结束更新。 该块触发所有tableView几何的重新加载。 而且,这个块是animation的,最终给出了行扩展的印象。

希望这是有益的,帕维尔

Pawel的beginUpdates / endUpdates技巧很好,我经常使用它。 但在这种情况下,您只需重新加载正在更改状态的行,确保您正确地使用所需的单元格types重新加载它们,并返回正确的新单元格高度。

以下是我想要完成的一个完整的工作实现:

。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 

如果你不想重新加载单元格(你想保留现有的单元格,只是改变大小,并可能添加/删除一些子视图),那么简单地执行didSelectRowAtIndexPath:中的beginUpdates / endUpdates技巧,然后调用一些方法你的手机煽动布局的变化。 beginUpdates / endUpdates将提示tableView重新查询每个单元格的高度 – 所以一定要返回正确的值。

在你的项目中创build一个UITableviewcell的子类。 创build这个类的笔尖,并将其父项设置为您的项目中的类与tableview和重写它的 –

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

在此类中编写方法contractCell()和expandCell(),并在expandCell方法中提供所需单元格的高度。 根据一些标志来适当地调用这个方法来识别细胞处于展开状态还是收缩状态。 使用你的tableview的

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

方法来处理单元格的select。

用这个replace你的cellForRowAtIndexPath函数。

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

创build一个数组wof字典,其中有一个按键Select_sts在开始时为0,当点击它的变化时1给你换表

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