我试图在我正在工作的应用程序中使用故事板。在应用程序中有列表和用户,每个列表都包含其他列表的集合(列表的成员,用户拥有的列表)。因此,相应地,我有ListCell和UserCell类。目标是让那些是可重用的整个应用程序(即,在任何我的tableview控制器)。

这就是我遇到问题的地方。

我如何在故事板中创建一个可以在任何视图控制器中重用的自定义表视图单元格?

以下是我目前为止尝试过的具体方法。

In Controller #1, added a prototype cell, set the class to my UITableViewCell subclass, set the reuse id, added the labels and wired them to the class's outlets. In Controller #2, added an empty prototype cell, set it to the same class and reuse id as before. When it runs, the labels never appear when the cells are shown in Controller #2. Works fine in Controller #1. Designed each cell type in a different NIB and wired up to the appropriate cell class. In storyboard, added an empty prototype cell and set its class and reuse id to refer to my cell class. In controllers' viewDidLoad methods, registered those NIB files for the reuse id. When shown, cells in both controllers were empty like the prototype. Kept prototypes in both controllers empty and set class and reuse id to my cell class. Constructed the cells' UI entirely in code. Cells work perfectly in all controllers.

在第二种情况下,我怀疑原型总是覆盖NIB,如果我杀死了原型单元格,为重用id注册我的NIB就可以了。但这样我就不能从单元格设置segue到其他帧,这就是使用故事板的全部意义。

在一天结束的时候,我想要两件事:在故事板中连接基于tableview的流,并在视觉上定义单元格布局,而不是在代码中定义。到目前为止,我还不知道怎么把它们都弄到。


当前回答

我找到了一种方法,为相同的VC加载单元格,没有测试segue。这可能是在单独的nib中创建单元格的一种变通方法

假设你有一个VC和两个表,你想在故事板中设计一个单元格,并在两个表中使用它。

(例如:一个表和一个搜索字段,一个UISearchController的结果表,你想在两者中使用相同的Cell)

当控制器要求单元格这样做:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString * identifier = @"CELL_ID";

    ContactsCell *cell = [self.YOURTABLEVIEW dequeueReusableCellWithIdentifier:identifier];
  // Ignore the "tableView" argument
}

这里有来自故事板的单元格

其他回答

我一直在寻找这个问题,我找到了理查德·维纳布尔的答案。这对我很管用。

iOS 5在UITableView上包含了一个新方法:registerNib:forCellReuseIdentifier: 要使用它,将UITableViewCell放在nib中。它必须是唯一的根 对象。 你可以在加载tableView后注册nib,然后当你 call dequeueReusableCellWithIdentifier:使用单元格标识符,它 将从笔尖拉它,就像如果你使用了一个故事板 原型细胞。

斯威夫特3

BJ Homer gave an excellent explanation, It helps me understand the concept. To make a custom cell reusable in storyboard, which can be used in any TableViewController we have to mix the Storyboard and xib approach. Suppose we have a cell named as CustomCell which is to be used in the TableViewControllerOne and TableViewControllerTwo. I am making it in steps. 1. File > New > Click File > Select Cocoa Touch Class > click Next > Give Name Of your class(for example CustomCell) > select Subclass as UITableVieCell > Tick the also create XIB file checkbox and press Next. 2. Customize the cell as you want and set the identifier in attribute inspector for cell, here we ll set as CellIdentifier. This identifier will be used in your ViewController to identify and reuse the Cell. 3. Now we just have to register this cell in our ViewController viewDidLoad. No need of any initialization method. 4. Now we can use this custom cell in any tableView.

在TableViewControllerOne

let reuseIdentifier = "CellIdentifier"

override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: reuseIdentifier)
} 

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier:reuseIdentifier, for: indexPath) as! CustomCell
    return cell!
}

b·j·荷马(BJ Homer)对正在发生的事情做出了出色的解释。

从实际的角度来看,我想补充一点,鉴于你不能将单元格作为xib并连接segue,最好的选择是将单元格作为xib -过渡比跨多个地方维护单元格布局和属性要容易得多,而且无论如何,你的segue可能与不同的控制器不同。你可以定义直接从你的表视图控制器到下一个控制器的segue,并在代码中执行它。

进一步的注意是,将单元格作为一个单独的xib文件会阻止你直接将任何动作等连接到表视图控制器(我还没有解决这个问题,无论如何-你不能将文件的所有者定义为任何有意义的东西)。我正在通过定义一个协议来解决这个问题,单元格的表视图控制器将遵循该协议,并在cellForRowAtIndexPath中添加控制器作为一个弱属性(类似于委托)。

我找到了一种方法,为相同的VC加载单元格,没有测试segue。这可能是在单独的nib中创建单元格的一种变通方法

假设你有一个VC和两个表,你想在故事板中设计一个单元格,并在两个表中使用它。

(例如:一个表和一个搜索字段,一个UISearchController的结果表,你想在两者中使用相同的Cell)

当控制器要求单元格这样做:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString * identifier = @"CELL_ID";

    ContactsCell *cell = [self.YOURTABLEVIEW dequeueReusableCellWithIdentifier:identifier];
  // Ignore the "tableView" argument
}

这里有来自故事板的单元格

我的理解是,你想:

在IB中设计一个可以在多个故事板场景中使用的单元格。 根据单元格所在的场景,从该单元格配置唯一的故事板segue。

不幸的是,目前还没有办法做到这一点。要理解为什么以前的尝试没有成功,您需要更多地了解故事板和原型表视图单元格是如何工作的。(如果你不关心为什么这些尝试没有成功,现在可以离开了。我没有什么神奇的解决办法,除了建议你提交一个bug。)

从本质上讲,故事板只不过是.xib文件的集合。当你从故事板中加载一个有一些原型单元格的表格视图控制器时,会发生这样的事情:

Each prototype cell is actually its own embedded mini-nib. So when the table view controller is loading up, it runs through each of the prototype cell's nibs and calls -[UITableView registerNib:forCellReuseIdentifier:]. The table view asks the controller for the cells. You probably call -[UITableView dequeueReusableCellWithIdentifier:] When you request a cell with a given reuse identifier, it checks whether it has a nib registered. If it does, it instantiates an instance of that cell. This is composed of the following steps: Look at the class of the cell, as defined in the cell's nib. Call [[CellClass alloc] initWithCoder:]. The -initWithCoder: method goes through and adds subviews and sets properties that were defined in the nib. (IBOutlets probably get hooked up here as well, though I haven't tested that; it may happen in -awakeFromNib) You configure your cell however you want.

这里需要注意的重要一点是,单元格的类和单元格的可视外观之间存在区别。您可以创建两个相同类的独立原型单元格,但是它们的子视图布局完全不同。事实上,如果你使用默认的UITableViewCell样式,这就是发生的事情。例如,“Default”样式和“Subtitle”样式都由同一个UITableViewCell类表示。

这一点很重要:单元格的类与特定的视图层次结构没有一对一的相关性。视图层次结构完全由注册到这个特定控制器的原型单元格中的内容决定。

还要注意,单元的重用标识符没有在某个全局单元药房中注册。重用标识符只在单个UITableView实例的上下文中使用。


有了这些信息,让我们看看在上述尝试中发生了什么。

在控制器#1中,添加一个原型单元格,将类设置为my UITableViewCell子类,设置重用id,添加标签并连接 他们到班级的出口。在控制器#2中,添加了一个空 原型单元格,将其设置为与之前相同的类和重用id。当 它运行时,当单元格显示时,标签从未出现 控制器# 2。在控制器#1中工作良好。

这是意料之中的。虽然两个单元格具有相同的类,但传递给控制器#2中的单元格的视图层次结构完全没有子视图。你得到了一个空单元格,这正是你在原型中所放的。

在不同的NIB中设计每种单元类型,并连接到 适当的单元格类。在故事板中,添加一个空的原型单元格 并设置它的类和重用id来引用我的单元格类。在 控制器的viewDidLoad方法,注册了那些NIB文件 重用id。控件中的单元格显示为空 原型。

这也是意料之中的。重用标识符在故事板场景或nib之间不共享,因此所有这些不同的单元具有相同的重用标识符是没有意义的。从tableview返回的单元格将具有与故事板场景中的原型单元格相匹配的外观。

This solution was close, though. As you noted, you could just programmatically call -[UITableView registerNib:forCellReuseIdentifier:], passing the UINib containing the cell, and you'd get back that same cell. (This isn't because the prototype was "overriding" the nib; you simply hadn't registered the nib with the tableview, so it was still looking at the nib embedded in the storyboard.) Unfortunately, there's a flaw with this approach — there's no way to hook up storyboard segues to a cell in a standalone nib.

保持两个控制器中的原型为空,并设置类和重用id 我的手机班。完全用代码构建单元格的UI。细胞 工作在所有控制器完美。

自然。希望这并不令人意外。


所以,这就是为什么它不起作用。你可以在独立的nibs中设计单元格,并在多个故事板场景中使用它们;你目前不能将故事板segue连接到那些单元格。不过,希望你在阅读这篇文章的过程中学到了一些东西。