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

22

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

这是否可能?我该如何做到这一点?


现在NSTableView支持NSTableCellView,我想知道是否有更好的方法来支持从IB完成所有操作。 - tofutim
10个回答

11

由于一些回答谈论了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/

希望对你有所帮助


11
这个问题是关于NSCell的子类的;其他答案似乎在做其他事情,可能是利用UITableViewCell作为视图。NSCell不是一个视图。虽然在IB中布局自定义单元格可能很有用,但我认为答案基本上是“不,这是不可能的”。当你子类化NSCell时,基本上只是在进行自己的绘制。它不支持子单元格或参数化的自动布局(如NSView的弹簧和托架),我怀疑这就是你想要的。唯一的例外是,你可以设计一个NSCell子类,它可以对子元素进行布局,并提供设置这些子元素及所有可调整参数的参数。然后,您需要编写一个IB插件,以使该单元格和相应的检查器在IB中的设计时间可用。不过,这可能比编写一个小的自定义应用程序更难。将NSCell放入窗口中间的控件中,并为自己创建UI,以调整您感兴趣的参数。绑定可以使此过程变得非常简单,以定位内容(例如,将x值绑定到滑块),尽管您当然无法直接操作元素。完成后,您可以在运行时归档单元格并在您的真实应用程序中加载它,或者您可以仅记录属性并在您的应用程序中以代码方式设置它们。

7
正如Ken所说,NSCellsNSViews是不同的,只有在NIB中才能布局NSView层次结构,而不是NSCells(它们没有任何明确的层次结构)。
另一方面,没有什么阻止你拥有一个NSViews的层次结构,并使用它来绘制你的NSCell - 你可以将它们添加为单元格父视图的子视图,告诉它们显示,并从窗口中删除它们,没有人会发现。
在这种情况下,使用NIB会起作用,尽管似乎很麻烦。通常我只是用一个自定义对象替换了接受NSCells的对象,而用我的NSViews,但这意味着编写自己的鼠标处理代码,这非常棘手。
另一方面,我的方法允许您在NIB中绑定视图的值,因此您不必做任何额外的工作,这很酷。

5
在IB中,创建一个空的XIB文件。然后打开Palette并拖动一个UITableViewCell到XIB中,双击它以进行编辑。
确保只包含自定义的UITableViewCell(没有其他UIView或其他顶级控件) - 确认在IB中这是真正的UITableViewCell,否则您无法设置重用标识符(而不是将UIView在IB中转换为自定义的UITableViewCell类)。
接下来,可以在单元格中添加标签或任何您喜欢的内容,同时设置重用标识符或者设置您想要的disclosure indicator。
在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];
}

如果你有任何标签或其他控件要在代码中引用,可以将它们与自定义单元格类一起连接 - 而不是文件的所有者。使用上述代码,你永远不需要设置文件的所有者(可以将其保留为NSObject)。
注:我注意到你实际上正在寻找一个NSCell答案,但在Cocoa中使用IB的代码方法应该与我以上所用的Cocoa Touch代码相同。因为loadNibNamed是一个标准的Cocoa调用。

我第一次做错了,但您详细的指导(起始)拯救了这一天。谢谢! - JOM

2

几年前,Joar Wingfors为Stepwise撰写了一篇相关主题的文章,TableView行中的Subviews

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

另一个可能性是,如果您可以针对Leopard,那么请查看是否需要使用NSTableView或者是否可以使用NSCollectionView。集合视图直接处理“项目视图”,而不是单元格,因此在Interface Builder中设计它们更加简单明了。


1

我找到了一些有趣的例子,但是我并不完全理解。

最后两个示例使用 NSTableViewDataSourceNSTableViewDelegate。我想在 InterfaceBuilder 中使用 BindingsArrayController 来连接其他 UI 元素,如文本字段。


0

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

从iOS 5开始,UITableView有一个方法

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

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

- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier

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


0
我是这样做的:
/* 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);
}

然而,它并不是非常高效的,如果你正在加载大量数据,它可能会对你造成影响。当然,你应该使用一个重用标识符(reuseIdentifier),这应该强制该代码每个表只运行几次。


1
这个问题是关于Cocoa的,不是关于Cocoa Touch的。 - srgtuszy

0

1) 创建 NSViewController TableViewCell.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;

希望这能有所帮助 =)

-1
将您的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;

虽然不值得扣分。 - evdude100

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接