是否可以在 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 所说,NSCells
和 NSViews
是不同的,您只能在 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 个示例适用于 NSTableViewDataSource
和 NSTableViewDelegate
。我想在InterfaceBuilder
中使用Bindings
和ArrayController
来连接文本字段等其他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) 创建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;
希望这会有所帮助 =)
【讨论】:
【参考方案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 和 Auto Layout 中说“使这个 UILabel 以另一个 UILabel 的中心为中心”? [关闭]