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

时间:2010-06-17 22:37:51

标签: 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);
}

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

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

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

有什么想法吗?

5 个答案:

答案 0 :(得分:94)

Apple的做法非常简单。

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

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

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

然后,当您拥有当前选择的索引时,您可以告诉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几何体。此外,该块是动画的,最终给出了行扩展的影响。

希望这有用, 的Pawel

答案 1 :(得分:5)

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

以下是我认为您正在努力实现的完整工作实施:

·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重新查询每个单元格的高度 - 所以一定要返回正确的值。

答案 2 :(得分:2)

创建一个在项目中继承UITableviewcell的类。创建此类'nib并使用tableview将其父级设置为项目中的类,并覆盖其 -

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

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

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

处理细胞选择的方法。

答案 3 :(得分:0)

用这个替换你的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; 
    }
    }

答案 4 :(得分:-1)

创建数组wof字典,其中有一个键Select_sts,当单击其更改1时,它在开始时为0 你改变了表格

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

}