在 UICollectionViewCell 中使用 Storyboard 中的自动布局约束

Posted

技术标签:

【中文标题】在 UICollectionViewCell 中使用 Storyboard 中的自动布局约束【英文标题】:Using Autolayout constraints from Storyboard in UICollectionViewCell 【发布时间】:2015-08-19 10:08:18 【问题描述】:

我正在为我的UICollectionView 使用自定义UICollectionViewCell 类。我必须在我的自定义类中使用 addSubview,因为我使用的是 FirebaseUI-ios。这就是我的 MessageCollectionViewCell 的样子:

import Foundation
import UIKit
class MessageCollectionViewCell: UICollectionViewCell 
    @IBOutlet var messageContainerView: UIView?
    @IBOutlet var messageText: UILabel?
    @IBOutlet var messageDisplayName: UILabel?
    @IBOutlet var messageUserImage: UIImageView?
    @IBOutlet var messageUserImageOverlay: UIView?

    override init(frame: CGRect) 
        super.init(frame: frame)

        // Custom initialization code for label
        let size = self.contentView.frame.size
        let frame = CGRectMake(0.0, 0.0, size.width, size.height)

        self.messageContainerView = UIView(frame: frame)
        self.messageUserImageOverlay = UIView(frame: frame)
        self.messageText = UILabel(frame: frame)
        self.messageDisplayName = UILabel(frame: frame)

        self.messageContainerView!.addSubview(self.messageUserImageOverlay!)
        self.messageContainerView!.addSubview(self.messageText!)
        self.messageContainerView!.addSubview(self.messageDisplayName!)
        self.contentView.addSubview(messageContainerView!)
    

    required init(coder aDecoder: NSCoder) 
        println("Init")
        super.init(coder: aDecoder)
    

我的 Storyboard 文件中有我想要使用的约束,但是当我使用 addSubview 时,我的约束没有被使用。无论如何我可以使用 addSubview() 并且仍然保持约束吗?我知道我可以通过编程方式添加它,但我希望使用我已经在 Storyboard 中设置的约束。

【问题讨论】:

看起来与此有关:***.com/questions/13224090/…。看起来github.com/firebase/FirebaseUI-iOS/blob/master/FirebaseUI/… 会导致原型单元格被覆盖。您还可以为 FirebaseCollectionViewDataSource 使用 XIB 构造函数,并且仍然有一个自定义类。这应该从 XIB 和自动布局中引入约束,这比原型单元更强大。 【参考方案1】:

此问题是由于 FirebaseUI 'FirebaseCollectionViewDataSource` 是如何注册其类的。我不相信有可能像你问的那样实例化这样的类并从 XIB 中获取自动布局属性,但可以通过修复我们对原型单元格的处理来解决问题。

这里的问题是我们两次注册单元格重用标识符:一次在情节提要中,一次在代码中(FirebaseCollectionViewDataSource 必须这样做才能使单元格出列)。由于我们称我们为第二个,它会覆盖第一个,这意味着您的插座都没有填充,布局很奇怪等。这意味着您必须像使用常规子类而不是 XIB 一样设置它们。您可以在这里做的最快的事情就是使用 XIB 而不是原型单元(它只是情节提要中的 XIB)。那么,我们如何才能支持 FirebaseUI + 原型单元...

简短的回答是,由于 Apple 的 UICollectionView 设计,目前无法使用此功能。

不像UITableView,它可以通过出列一个单元格来检查这个行为(这将返回一个实例化的原型单元格并告诉我们重用标识符已经创建)就像我们在FirebaseTableViewDataSourcehere,@987654326中所做的那样@ 没有提供类似的方法,它只给出:

func dequeueReusableCellWithReuseIdentifier(_ identifier: String,
                           forIndexPath indexPath: NSIndexPath!) -> AnyObject

鉴于此方法需要一个indexPath,因为它已经返回一个非零对象,当我们尝试在初始化时读取任意对象时,它将抛出一个NSInternalInconsistencyException(因为不存在可供读取的项目)。此外,似乎没有任何方法可以以编程方式检查 reuseIdentifier 是否正在使用中。这给我们留下了几个选择:

    建议人们不要使用原型单元,而是使用自定义子类或 XIB 并将它们挂钩。情节提要和原型单元感觉有点脆弱(主要是因为这样的原因),但它们绝对易于使用。李> 从FirebaseCollectionViewDataSource 中拉出-registerClass: forReuseIdentifier: 调用,尽管这意味着FirebaseTableViewDataSource 也应该更改(即使它可以工作)并让开发人员显式调用它(或者在使用故事板)。 将情节提要的参数添加到初始化调用中,该参数仍将保留reuseIdentifier 以使单元格出列,但不注册类。 尝试使单元格出列,捕获NSException,注册类并重试。这可行,但它仍然会引发异常并在运行循环中添加更多代码(我们必须使用我们知道最多会失败一次的 try-catch 来包装调用)。

我个人的偏好是 1,但原型单元的价值主张足够高,以至于 3 可能是这个库的最佳选择。我宁愿不做 2,因为小区注册是一个够难的问题。

目前,我建议使用 XIB 代替原型单元,或者等待我们选择上述解决方案之一(我们可以很快发布版本来解决问题)。

【讨论】:

以上是关于在 UICollectionViewCell 中使用 Storyboard 中的自动布局约束的主要内容,如果未能解决你的问题,请参考以下文章

在 UICollectionViewCell 中更新 UITableView

如何在 UICollectionViewCell 中添加 UICollectionView?

如何在 UICollectionViewCell 上设置 UILabel?

UICollectionViewCell 边框/阴影

如何在 iOS 7 中刷新 UICollectionViewCell?

UICollectionviewcell 中未显示数据?