是否可以在 Interface Builder 中设计 NSCell 子类?

Posted

技术标签:

【中文标题】是否可以在 Interface Builder 中设计 NSCell 子类?【英文标题】:Is it possible to design NSCell subclasses in Interface Builder? 【发布时间】:2008-10-14 19:19:55 【问题描述】:

我正在尝试将 NSCell 子类化以在 NSTableView 中使用。我要创建的单元格相当复杂,所以如果我可以在 Interface Builder 中设计它然后从 nib 加载 NSCell 将会非常有用。

这可能吗?我该怎么做?

【问题讨论】:

既然 NSTableView 支持 NSTableCellView,不知道有没有更好的方法来支持从 IB 做所有事情。 【参考方案1】:

问题是关于 NSCell 的一个子类;其他答案似乎在做其他事情,可能是利用 UITableViewCell 作为视图。

NSCell 不是视图。虽然在 IB 中放置自定义单元将是一件有用的事情,但我认为答案基本上是“不,这是不可能的”。当你继承 NSCell 时,你几乎只是在做你自己的绘图。不支持子单元格或参数化的自动布局(ala NSView 的弹簧和支柱),我怀疑你在寻找什么。

唯一需要注意的是,您可以设计一个 NSCell 子类,确实对子元素进行布局,并提供用于设置这些子元素和所有可调整参数的参数。然后,您需要编写一个 IB 插件,以使该单元格和随附的检查器在 IB 中的设计时可用。

然而,这可能比编写一个或多或少做相同事情的小定制应用程序更难。将 NSCell 放在窗口中间的控件中,并自己制作 UI 以调整您感兴趣的参数。绑定可以使定位内容变得非常简单(即将 x 值绑定到滑块),尽管您会当然不能直接操纵元素。完成后,您可以存档您的单元格并在运行时在您的真实应用中加载存档,或者您可以直接注销属性并在您的应用中的代码中设置它们。

【讨论】:

【参考方案2】:

这个线程中的一些答案已经跑题了,因为他们在谈论 Cocoa Touch,而最初的问题是关于 Cocoa - 这两个 API 在这方面有很大的不同,而 Cocoa Touch 很容易,因为 UITableViewCell 是一个视图子类. NSCell 不是,这就是问题所在

关于信息,我最近不得不在 NSOutlineView 中做一些非常相似的事情 - 这基本上是相同的,但如果有的话,会有点困难,因为你必须处理关卡的披露/崩溃。如果您对代码感兴趣,我在此处发布了相关信息:http://www.stevestreeting.com/2010/08/08/cocoa-tip-using-custom-table-outline-cells-designed-in-ib/

HTH

【讨论】:

正是我想要的【参考方案3】:

正如 Ken 所说,NSCellsNSViews 是不同的,您只能在 NIB 中布置 NSView 层次结构,而不是 NSCells(没有任何明确的层次结构)。

另一方面,没有什么可以阻止您拥有NSViews 的层次结构并使用它来绘制您的NSCell - 您可以将它们添加为单元格父视图的子视图,告诉它们显示,然后把它们从窗户上移开,没有人会更聪明。

在这种情况下,使用 NIB 是可行的,尽管它看起来很麻烦。通常,我只是将采用 NSCells 的对象替换为采用我的 NSViews 的自定义对象,但这意味着要编写自己的鼠标处理代码,这非常棘手。

另一方面,我的方法允许您在 NIB 中绑定视图的值,因此您不必做任何额外的工作,这很酷。

【讨论】:

【参考方案4】:

在 IB 中,启动一个空的 XIB。现在转到调色板并拖入一个 UITableViewCell,双击调出并进行编辑。

仅包含自定义 UITableViewCell(没有其他 UIView 或其他***控件) - 确保它是 IB 中的真实 UITableViewCell,否则您无法设置重用标识符(而不是将 IB 中的 UIView 强制转换为自定义 UITableViewCell 类) . 然后,您可以在单元格中添加标签或您喜欢的任何内容,以及设置重用标识符或设置您可能喜欢的任何披露指示符。

要使用,您在 tableView:cellForRow:atIndexPath: 方法中提供这样的代码:

YourCustomCellClass *cell = (YourCustomCellClass *)[tableView dequeueReusableCellWithIdentifier:<IDYouSetInXIBFile>];
if ( cell == nil )

        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:<YourXIBName> owner:self options:nil];
    id firstObject = [topLevelObjects objectAtIndex:0];
    if ( [ firstObject isKindOfClass:[UITableViewCell class]] )
        cell = firstObject; 
    else cell = [topLevelObjects objectAtIndex:1];

如果您想在代码中引用任何标签或其他控件,请在 IB 中将它们连接到您的自定义单元类 - 而不是文件的所有者,您不需要使用上述代码进行设置(您可以离开它作为 NSObject)。

编辑:我注意到您确实在寻找 NSCell 答案,但是在 Cocoa 中使用 IB 的代码方法应该与我上面使用的 Cocoa Touch 代码相同,因为 loadNibNamed 是标准的 Cocoa 调用。

【讨论】:

不知何故我第一次做错了,但你的详细说明(开始)挽救了一天。谢谢!【参考方案5】:

几年前,Joar Wingfors 为 Stepwise 写了一篇关于相关主题 Subviews in TableView Rows 的文章。

主要技术是创建一个可以承载 NSView 的 NSCell。如果您要这样做,您可以在 Interface Builder 中设计一个 NSView 子类,您可以将它嵌入到您需要该特定单元格的任何位置。

如果您可以定位 Leopard,另一种可能性是查看您是否需要使用 NSTableView 或是否可以使用 NSCollectionView。集合视图直接根据“项目视图”而不是单元格来处理,因此在 Interface Builder 中设计它们要简单得多。

【讨论】:

【参考方案6】:

我发现了一些有趣的例子,但我并不完全理解。

GitX 在他们的PBIconAndTextCell 中扩展了NSTextFieldCell,引用了这个post。 WWDC 2009 - 第 110 节“使用表格视图和浏览器呈现用户数据”讨论“添加子视图”和“自定义单元格编辑器”。 (不过我没有源代码。) Display an NSTextfieldCell containing text and an image within a NSTableView, #70 Display an NSTextfieldCell containing text and an image within a NSTableView, #71

最后 2 个示例适用于 NSTableViewDataSourceNSTableViewDelegate。我想在InterfaceBuilder 中使用BindingsArrayController 来连接文本字段等其他UI 元素。

我偶然发现了another discussion,其中Abizern 指出PXListView by Alex Rozanski 看起来很有前途!

我正在尝试自己实施该问题的解决方案。请找到我的project on github 和最新的rendering problems over here。

【讨论】:

【参考方案7】:

我是这样做的:

/* example of a silly way to load a UITableViewCell from a standalone nib */

+ (CEntryTableViewCell *)cell

// TODO -- this is really silly.
NSArray *theObjects = [[NSBundle mainBundle] loadNibNamed:@"EntryTableViewCell" owner:self options:NULL];
for (id theObject in theObjects)
    if ([theObject isKindOfClass:self])
        return(theObject);
NSAssert(NO, @"Could not find object of class CEntryTableViewCell in nib");
return(NULL);

但是它的效率不是很高,如果您要加载大量数据,它可能会伤害到您。当然,您应该使用重用标识符,它应该强制此代码在每个表中只运行几次。

【讨论】:

问题是针对 Cocoa,而不是 Cocoa Touch【参考方案8】:

1) 创建NSViewControllerTableViewCell.h

2) 在TableViewCell.h 中创建一些类似的程序

-(void)setText:(NSString *)text image:(NSImage *)image

3) 在主类#import "TableViewCell.h"

4) 在-(NSView *)tableView:viewForTableColumn:row: write: 的主类中

NSImage *img = //some image
TableViewCell *cell = [[TableViewCell alloc] initWithWindowNibName:@"TableViewCell"];
cell.view.init;
[cell setText:@"some text" image:img];
return cell;

希望这会有所帮助 =)

【讨论】:

【参考方案9】:

我想在这里提供一种更现代的方法。

ios 5 开始,UITableView 有了方法

(void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier

一旦您注册了包含您的单元格的 NIB,只需使用

- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier

获取一个新的单元格。如果一个单元格可供重用,它将被返回,否则会自动创建一个新单元格,在这种情况下,这意味着从 NIB 文件中加载。

【讨论】:

【参考方案10】:

将您的UITableViewCell 添加到您的tableviewcontroller 并声明IBOutlet 属性:

@interface KuguTableViewController : UITableViewController 
    IBOutlet UITableViewCell *customTypeCell;


@property (readonly)  UITableViewCell *customTypeCell;

...然后在cellForRowAtIndexPath 中,您可以使用您的单元格并将其设置为重复使用:

static NSString *CellIdentifier = @"CustomCell"
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
        cell = customTypeCell;
        cell.reuseIdentifier = CellIdentifier;

【讨论】:

虽然不值得减分。

以上是关于是否可以在 Interface Builder 中设计 NSCell 子类?的主要内容,如果未能解决你的问题,请参考以下文章

是否可以在 Interface Builder 中并排显示相同的视图控制器纵向和横向?

从 Interface Builder 下拉列表中删除已删除的图像

在 Interface Builder 中使用常量

是否可以在 Interface Builder 和 Auto Layout 中说“使这个 UILabel 以另一个 UILabel 的中心为中心”? [关闭]

在 Interface Builder 中删除自动布局(约束)

在 Interface Builder 中显示在代码中创建的 UIButton