展开单元格以显示 nib 文件视图

Posted

技术标签:

【中文标题】展开单元格以显示 nib 文件视图【英文标题】:expanding cell to show a nib file view 【发布时间】:2013-04-13 22:31:17 【问题描述】:

我想在选中时展开单元格以显示如上图所示的一行按钮。我有一个xib 文件,其中显示了一个 320 宽 x 140 高的单元格。我已经将 UITableViewCell 子类化了。此外,我还有另一个 xib 文件,其中有一排按钮,如上图中的蓝色墨水所示。

我可以使用initWithCoder 使用这个答案from a really smart guy 加载按钮行!

但是,它会覆盖 MyCustomCell 中的所有其他视图。

如何在单元格展开时加载 xib,使其位于 140pt 高单元格的下半部分?

【问题讨论】:

【参考方案1】:

在进行了更多研究后,我发现了一种不同的方法,可以只使用一个单元格来执行您想要的操作。在此方法中,您只有较高的单元格,但返回的高度只能让您看到单元格的上半部分,除非它被选中。你必须在你的细胞设计中做两件事来完成这项工作。首先在 IB 中选择“剪辑子视图”框,这样按钮就不会显示在它们的视图(单元格)之外。其次,进行约束,使按钮全部相互垂直排列,并为其中一个在单元格顶部的 UI 元素之一提供垂直间距约束。确保没有任何按钮对单元格底部有约束。通过这样做,按钮将与顶部元素保持固定距离(与单元格顶部应该有固定的空间),这将导致它们在单元格较短时被隐藏。要动画高度变化,您所要做的就是在表格视图上调用 beginUpdates 和 endUpdates。

#import "TableController.h"
#import "TallCell.h"

@interface TableController ()
@property (strong,nonatomic) NSArray *theData;
@property (strong,nonatomic) NSIndexPath *selectedPath;
@end

@implementation TableController 


- (void)viewDidLoad 
    [super viewDidLoad];
    [self.tableView registerNib:[UINib nibWithNibName:@"TallCell" bundle:nil] forCellReuseIdentifier:@"TallCell"];
    self.theData = @[@"One",@"Two",@"Three",@"Four",@"Five",@"Six",@"Seven",@"Eight",@"Nine"];
    [self.tableView reloadData];




- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
    return self.theData.count;


-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
    if ([indexPath isEqual:self.selectedPath]) 
        return 88;
    else
        return 44;
    


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 

    TallCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TallCell" forIndexPath:indexPath];
    cell.label.text = self.theData[indexPath.row];
    return cell;



#pragma mark - Table view delegate

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

    if ([self.selectedPath isEqual:indexPath]) 
        self.selectedPath = nil;
    else
        self.selectedPath = indexPath;
    

    [tableView beginUpdates];
    [tableView endUpdates];

我认为,当您选择第一个单元格时,它会为您提供所需的动画,但如果您随后选择当前所选单元格下方的单元格,则会得到一些不同的动画。我不知道有什么办法。

【讨论】:

我到处寻找如何剪辑子视图。感谢您将其包含在您的解释中!我仍在尝试通过扩展单元格高度来完成这项工作,并且仍然让下面的单元格像上面的单元格一样工作。 我发现解决它的一种方法是使用 reloadRowsAtIndexpath 方法。不幸的是,这也会更新单元格。我想知道我们是否可以在不丢失行数据的情况下重新加载它的 beginupdate 部分......【参考方案2】:

我不确定您的两个 xib 文件中有什么,但我的做法是为较短的单元格设置一个 xib 文件,为较高的单元格设置一个 xib 文件(其中包含您显示的所有内容在你的图中)。我是这样做的,上面提到了两个 xib 文件:

#import "TableController.h"
#import "ShortCell.h"
#import "TallCell.h"

@interface TableController ()
@property (strong,nonatomic) NSArray *theData;
@property (strong,nonatomic) NSIndexPath *selectedPath;
@end

@implementation TableController 


- (void)viewDidLoad 
    [super viewDidLoad];
    [self.tableView registerNib:[UINib nibWithNibName:@"ShortCell" bundle:nil] forCellReuseIdentifier:@"ShortCell"];
    [self.tableView registerNib:[UINib nibWithNibName:@"TallCell" bundle:nil] forCellReuseIdentifier:@"TallCell"];
    self.theData = @[@"One",@"Two",@"Three",@"Four",@"Five",@"Six",@"Seven",@"Eight",@"Nine"];
    [self.tableView reloadData];




- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
    return self.theData.count;


-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
    if ([indexPath isEqual:self.selectedPath]) 
        return 88;
    else
        return 44;
    


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 

    if (! [self.selectedPath isEqual:indexPath]) 
        NSLog(@"returning short");
        ShortCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ShortCell" forIndexPath:indexPath];
        cell.label.text = self.theData[indexPath.row];
        return cell;
    else
        NSLog(@"returning long");
        TallCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TallCell" forIndexPath:indexPath];
        cell.label.text = self.theData[indexPath.row];
        return cell;
    




#pragma mark - Table view delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    if ([self.selectedPath isEqual:indexPath]) 
        self.selectedPath = nil;
        [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
        return;
    

    NSIndexPath *lastSelectedPath = self.selectedPath;
    self.selectedPath = indexPath;
    if (lastSelectedPath != nil) 
         [self.tableView reloadRowsAtIndexPaths:@[indexPath,lastSelectedPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    else
        [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    

【讨论】:

我试过了,效果很好。但是,当我再次单击 selectedCell 时,它会使应用程序崩溃。有任何想法吗?另外,我注意到它并没有完全执行像手风琴一样扩展单元格以显示按钮行的所需行为。它在新的 TallCell 代替 ShortCell 中有点消失。知道如何创建这种效果吗? @AlanMond,对不起,我忘了考虑选择已经展开的同一行。我编辑了我的答案来解决这个问题。我不知道如何显示底部的扩展。 是的,解决了!你能解释一下 [self.tableview reloadRowsAtIndexPaths:@[indexPath, lastSelectedPath] ... 我不明白 lastSelectedPath 如何让高单元格出现,并隐藏短单元格。 @AlanMond,lastSelectedIndexPath 只是跟踪先前选择的行。重新加载行时,您需要更改新选择的行和已选择的行。导致一个高而另一个矮的事情就是哪一行是选定的行(保存在属性 selectedPath 中)—— heightForRowAtIndexPath 和 cellForRowAtIndexPath 中的 if 语句确定行的高度,以及哪个单元格(高或短) 被返回。

以上是关于展开单元格以显示 nib 文件视图的主要内容,如果未能解决你的问题,请参考以下文章

如何在 didselect 上展开 collectionview 单元格以显示更多信息?

如何展开 MUI 数据表中的单元格以显示其他内容?

调整表格视图单元格以显示 UITextView 和 UIWebView

Nib 文件中的静态单元格未显示

如何按下 tableview 单元格以在导航控制器中显示带有文本的视图控制器

自定义 UITableView 单元格 Nib 文件仅在选择单元格后显示?