UITableViewCell展开点击

可以说我们有一个自定义的UITableViewCell

所以,每当我点击单元格上的自定义button..它应该扩大到一定程度(你可以说40高度更多…),当我再次点击相同的自定义button应该崩溃到以前的高度。

开发者请引导我..我怎么能实现这个任务

实现heightForRowAtIndexPath来计算正确的高度。 然后在你的button的代码中,强制table使用beginUpdates plus endUpdates重新评估每个单元格的高度:

[self.tableView beginUpdates]; [self.tableView endUpdates]; 

tableview单元格高度的变化将自动用heightForRowAtIndexPath来计算,变化也会animation。

事实上,而不是你的单元格上这样做的button,你甚至可以select单元格做didSelectRowAtIndexPath

考虑到这是完全正确的,我不打算在这里说出与公认的答案相抵触的任何内容。 不过,我将详细介绍如何完成这个任务。 如果你不想阅读所有这些,并且更喜欢在工作项目中使用源代码,我已经上传了一个示例项目到GitHub 。

基本的想法是在方法-tableView: heightForRowAtIndexPath:有一个条件,它决定了当前单元格是否应该被展开。 这将通过在-tableView: didSelectRowAtIndexPath:内调用表上的开始/结束更新来触发-tableView: didSelectRowAtIndexPath:在本例中,我将演示如何创build一个允许一次展开一个单元格的表视图。

你需要做的第一件事是声明一个NSIndexPath对象的引用。 你可以做到这一点,但我build议使用这样的属性声明:

 @property (strong, nonatomic) NSIndexPath *expandedIndexPath; 

注意:您不需要在viewDidLoad或任何其他类似的方法内创build此索引path。 索引最初为零的事实只意味着表格最初不会有扩大的行。 如果你想让表格从你select的行开始,你可以在viewDidLoad方法中添加这样的内容:

 NSInteger row = 1; NSInteger section = 2; self.expandedIndexPath = [NSIndexPath indexPathForRow:row inSection:section]; 

下一步是开始你的UITableViewDelegate方法-tableView: didSelectRowAtIndexPath:添加逻辑来根据用户select来改变扩展的单元-tableView: didSelectRowAtIndexPath:引。 这里的想法是检查刚刚被选中的索引path是否存储在expandedIndexPathvariables中存储的索引path中。 如果两者匹配,那么我们知道用户正试图取消select扩展的单元格,在这种情况下,我们将该variables设置为零。 否则,我们将expandedIndexPathvariables设置为刚刚select的索引。 这一切都在beginUpdates / endUpdates调用之间完成,以允许表视图自动处理过渡animation。

 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView beginUpdates]; // tell the table you're about to start making changes // If the index path of the currently expanded cell is the same as the index that // has just been tapped set the expanded index to nil so that there aren't any // expanded cells, otherwise, set the expanded index to the index that has just // been selected. if ([indexPath compare:self.expandedIndexPath] == NSOrderedSame) { self.expandedIndexPath = nil; } else { self.expandedIndexPath = indexPath; } [tableView endUpdates]; // tell the table you're done making your changes } 

然后最后一步是另一个UITableViewDelegate方法-tableView: heightForRowAtIndexPath: 此方法将在您为表确定需要更新的每个索引path触发beginUpdates之后调用。 这是您将expandIndexPath与当前正在重新评估的索引path进行比较的位置。

如果两个索引path是相同的,那么这是你希望展开的单元格,否则它的高度应该是正常的。 我用了100和44的值,但是你可以使用任何适合你的需求。

 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { // Compares the index path for the current cell to the index path stored in the expanded // index path variable. If the two match, return a height of 100 points, otherwise return // a height of 44 points. if ([indexPath compare:self.expandedIndexPath] == NSOrderedSame) { return 100.0; // Expanded height } return 44.0; // Normal height } 

我为此创build了一个开源库。 你只需在你的代码中实现崩溃并展开代表,然后 ! 您也可以执行任何绘图和animation。 看看这个 。

在这里输入图像说明

我已经做了一个可重用的组件,将做你正在谈论的。 这很容易使用,并有一个演示项目。

GitHub上的GCRetractableSectionController 。

而不是使用[tableView beginUpdates][tableView endUpdates] ,我在didSelectRowAtIndexPath方法内使用[tableView reloadRowsAtIndexPath:... withRowAnimation:...]方法。

我更喜欢这个,因为当我使用begin&end更新方法展开我的UITableViewCell时,我遇到了一些应该显示的元素的问题。 另一点是,你可以select一些animation,如:顶部,底部,左,右…

我使用Gcamp的源代码并创build了自己的版本。

1)在loadView方法中,初始化一个可变数组,您将在其中保存部分的展开或非展开状态。 将扩展的状态保存在一个单独的数组中是非常重要的,当表视图滚动时不会被破坏(例如,如果将它存储在一个headerView中,它将被重绘,并且忘记它被展开的天气)。 在我的情况是_sectionStatuses数组。

 - (void)loadView { // At the beginning all sections are expanded _sectionStates = [NSMutableArray arrayWithCapacity:self.tableView.numberOfSections]; for (int i = 0; i < self.tableView.numberOfSections; i++) { _sectionStates[i] = [NSNumber numberWithBool:YES]; } } 

2)创build一个自定义的headerView的一个部分用于扩展的button。 使用委托模式将您的headerView中button的操作委托给您的TableViewController。 您可以在Gcamp的源代码中find合适的图像。

3)创build一个操作来删除或添加行。 这里_foldersArray是我的结构,它包含所有的数据。 我的部分的headerView – MCExpandableAccountHeaderView知道它是自己的部分编号 – 当我为每个部分创build标题视图时,我将其转移到那里。 把它转移到这个方法是很重要的,因为你必须知道哪个部分现在被扩展或拉伸了。

 - (void)expandClicked:(MCAccountHeaderView *)sender { MCExpandableAccountHeaderView *expandableAccountHeaderView = (MCExpandableAccountHeaderView*)sender; // Finding a section, where a button was tapped NSInteger section = expandableAccountHeaderView.section; // Number of rows, that must be in a section when it is expanded NSUInteger contentCount = [_foldersArray[section - 1][@"folders"] count]; // Change a saved status of a section BOOL expanded = [_sectionStates[section] boolValue]; expanded = ! expanded; expandableAccountHeaderView.expanded = expanded; _sectionStates[section] = [NSNumber numberWithBool:expanded]; // Animation in a table [self.tableView beginUpdates]; NSMutableArray* modifiedIndexPaths = [[NSMutableArray alloc] init]; for (NSUInteger i = 0; i < contentCount; i++) { NSIndexPath* indexPath = [NSIndexPath indexPathForRow:i inSection:section]; [modifiedIndexPaths addObject:indexPath]; } if (expandableAccountHeaderView.expanded) [self.tableView insertRowsAtIndexPaths:modifiedIndexPaths withRowAnimation:UITableViewRowAnimationFade]; else [self.tableView deleteRowsAtIndexPaths:modifiedIndexPaths withRowAnimation:UITableViewRowAnimationFade]; [self.tableView endUpdates]; // Scroll to the top of current expanded section if (expandableAccountHeaderView.expanded) [self.tableView scrollToRowAtIndexPath:INDEX_PATH(0, section) atScrollPosition:UITableViewScrollPositionTop animated:YES]; } 

4)根据是否扩展,在一个部分中返回正确的数字或​​行也是很重要的。

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { BOOL expanded = [_sectionStates[section] boolValue]; return expanded ? [_foldersArray[section - 1][@"folders"] count] : 0; } 
 initialize iSelectedIndex = -1; and declare UITableView *urTableView; - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ return 10; //Section count } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 3; //row count } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if(cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; } [cell.textLabel setText:[NSString stringWithFormat:@"sec:%d,row:%d",indexPath.section,indexPath.row]]; return cell; } - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{ // adding a label with the tap gesture to the header in each section headerLabel = [[UILabel alloc]init]; headerLabel.tag = section; headerLabel.userInteractionEnabled = YES; headerLabel.backgroundColor = [UIColor greenColor]; headerLabel.text = [NSString stringWithFormat:@"Header No.%d",section]; headerLabel.frame = CGRectMake(0, 0, tableView.tableHeaderView.frame.size.width, tableView.tableHeaderView.frame.size.height); UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(gestureTapped:)]; [headerLabel addGestureRecognizer:tapGesture]; return headerLabel; } - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{ return 50.0; //adjust the height as you need } - (void)gestureTapped:(UITapGestureRecognizer *)sender{ UIView *theSuperview = self.view; // whatever view contains CGPoint touchPointInSuperview = [sender locationInView:theSuperview]; UIView *touchedView = [theSuperview hitTest:touchPointInSuperview withEvent:nil]; if([touchedView isKindOfClass:[UILabel class]]) { if (iSelectedIndex != touchedView.tag) { //if new header is selected , need to expand iSelectedIndex = touchedView.tag; }else{ // if the header is already expanded , need to collapse iSelectedIndex = -1; } [urTableView beginUpdates]; [urTableView endUpdates]; } } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { // Show or hide cell float height = 0.0; if (indexPath.section == iSelectedIndex) { height = 44.0; // Show the cell - adjust the height as you need } return height; } 

要添加到0x7fffffff的答案,我发现我需要在didSelectRowAtIndexPath中的if语句的额外条件 – 因此:

 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView beginUpdates]; if (self.expandedIndexPath && [indexPath compare:self.expandedIndexPath] == NSOrderedSame) { self.expandedIndexPath = nil; } else { self.expandedIndexPath = indexPath; } [tableView endUpdates]; }