手风琴表格单元格 - 如何动态扩展/收缩uitableviewcell?

s.n*_*ave 60 iphone objective-c

我正在尝试创建一个手风琴类型的uitableviewcell,当用户选择单元格时,它会展开以显示内嵌的详细信息视图,类似于digg应用程序的工作方式.我最初尝试用cellForRowAtIndex中的customcell替换当前的tablecell但是动画看起来有点不稳定,因为你可以看到被替换的单元格,整体效果不好.

如果你看看digg应用程序以及其他已经完成此操作的应用程序,似乎它们不会替换当前的单元格,而是可能在单元格中添加子视图?然而,原始单元似乎根本没有动画,只有新视图符合表格.

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

更新: 我已经使用下面的neha方法取得了一些进展,同时单元格正在动画正确的方式,它会对表格中的其他单元格造成严重破坏.我所做的是使用自定义类子类化UITableViewCell,该类包含一个实际绘制视图的UIView实例,然后我将其添加到表格单元内容视图中.

- (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);
}
Run Code Online (Sandbox Code Playgroud)

以下是我正在使用的所有表委托方法:

- (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;           
} 
Run Code Online (Sandbox Code Playgroud)

现在看来,单元格正在扩展,但实际上并没有刷新,因此标签和文本字段都没有显示出来.然而,当我关闭并在屏幕上滚动单元格时,它们会显示出来.

有任何想法吗?

Paw*_*wel 94

Apple的方法很简单.

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

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

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

然后,当您拥有当前选择的索引时,您可以告诉tableView它应该为该行提供更多空间.

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

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

现在我们可以回到开始/结束更新.该块触发重载所有tableView几何体.此外,该块是动画的,最终给出了行扩展的影响.

帕维尔希望这很有帮助

  • 开始/结束更新是执行此操作的正确方法.不要在setSelected中添加新视图.相反,在创建单元格时添加它们,并将其隐藏值设置为YES.在layoutSubviews的实现中正确布局它们.当您选择单元格时,将其隐藏设置为NO,并在取消选择为YES时.您无需调用cellForRowAtIndexPath方法.没有它你可以做所有的自定义.亲切的问候,帕维尔 (6认同)
  • 由于您在didSelectCellForRowAtIndexPath:方法中调用了开始/结束更新,因此已经选择了该单元格.因此,您可以在单元实现中使用setSelected:animated:方法将其配置为选定状态. (5认同)

Tom*_*ift 5

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

以下是我认为您要完成的工作的完整工作:

.H:

#import <UIKit/UIKit.h>

@interface ExpandingTableViewController : UITableViewController 
{

}

@property (retain) NSIndexPath* selectedIndexPath;

@end
Run Code Online (Sandbox Code Playgroud)

.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
Run Code Online (Sandbox Code Playgroud)

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


neh*_*eha 2

创建一个类,该类是项目中 UITableviewcell 的子类。创建此类的笔尖并将其父级设置为带有表视图的项目中的类并覆盖其 -

(void)setSelected:(BOOL)selected animated:(BOOL)animated 
Run Code Online (Sandbox Code Playgroud)

在此类中编写方法contractCell()和expandCell(),并在expandCell方法中提供所需的单元格高度。根据设置的一些标志来适当地调用此方法,以识别细胞是否处于扩张状态或收缩状态。使用你的表格视图

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
Run Code Online (Sandbox Code Playgroud)

处理单元格选择的方法。