通常如何使用iOS 14单元内容配置?

通常如何使用iOS 14单元内容配置?,ios,uitableview,ios14,Ios,Uitableview,Ios14,我正在观看和重播WWDC 2020的“现代电池配置”,但启发作用并不明显 据我所知,内置ListContentConfiguration具有类似于内置单元格样式组件(如文本标签和图像视图)的属性。但我从不使用内置的单元格样式;我总是创建一个单元子类,在xib或故事板原型单元中从头开始设计单元子视图,甚至用代码构造它们 那么,我如何使用苹果的配置来填充我手机的子视图呢 视频说: 除了列表内容配置之外,我们还允许您访问实现所有呈现的关联列表内容视图。您只需使用配置创建或更新此视图,然后就可以将其作为

我正在观看和重播WWDC 2020的“现代电池配置”,但启发作用并不明显

据我所知,内置ListContentConfiguration具有类似于内置单元格样式组件(如文本标签和图像视图)的属性。但我从不使用内置的单元格样式;我总是创建一个单元子类,在xib或故事板原型单元中从头开始设计单元子视图,甚至用代码构造它们

那么,我如何使用苹果的配置来填充我手机的子视图呢

视频说:

除了列表内容配置之外,我们还允许您访问实现所有呈现的关联列表内容视图。您只需使用配置创建或更新此视图,然后就可以将其作为子视图添加到您自己的自定义视图旁边。这使您可以利用所有内容配置功能,并将ListContentView与其旁边的其他自定义视图(如额外的图像视图或标签)结合起来

好吧,不,那不是我想做的。我不想要任何内置单元样式的子视图

然后视频说:

即使在单元格内构建完全自定义的视图层次结构,也可以使用系统配置来提供帮助。 由于配置非常轻量级,因此可以将它们用作字体、颜色和边距等默认值的来源,并复制到自定义视图中,即使您从未直接应用配置本身。 对于更高级的用例,您可以使用成对的内容视图类创建一个完全自定义的内容配置类型来呈现它,然后使用自定义配置与使用列表内容配置相同的方式来处理任何单元格

我的斜体字和斜体字是我要问的部分。我在问:怎么做

  • 我知道有一个协议

  • 我理解,一致性类通过其
    方法将ContentView
    设置为“内容视图”,即具有
    配置
    属性的UIView(因为它符合UIContentConfiguration)

那么,如何将其与我的自定义单元格子类结合使用,将数据源中的信息传递给单元格,并填充单元格的子视图呢


像往常一样,苹果给我们展示了玩具的例子,完全忽略了在现实世界中如何工作的细节。有人知道了吗?

编辑我现在已经发表了一系列关于这个主题的文章,从


这里的关键——我认为苹果在视频中根本没有明确说明这一点——是这些单元配置的工作方式是从字面上撕下单元的
contentView
,并将其替换为配置提供的视图,作为其
makeContentView
的输出

因此,您所要做的就是手工构建整个内容视图,运行时将为您将其放入单元格中

这里有一个例子。我们需要提供采用UIContentConfiguration的我们自己的配置类型,以便我们可以定义我们自己的属性;它还必须实现
makeContentView()
更新(for:)
。假设我们有四个文本要显示在单元格中:

struct Configuration : UIContentConfiguration {
    let text1: String
    let text2: String
    let text3: String
    let text4: String
    func makeContentView() -> UIView & UIContentView {
        let c = MyContentView(configuration: self)
        return c
    }
    func updated(for state: UIConfigurationState) -> MyCell.Configuration {
        return self
    }
}
在现实生活中,我们可能会通过更改返回此配置的一个版本(某些属性已更改)来响应状态的更改,但在这种情况下没有什么可做的,所以我们只返回
self

我们假设MyContentView的存在,这是一个采用UIContentView的UIView子类,意味着它有一个
配置
属性。这是我们配置视图的子视图并应用配置的地方。在这种情况下,应用配置意味着只需设置四个标签的文本。我将把这两项任务分开:

class MyContentView: UIView, UIContentView {
    var configuration: UIContentConfiguration {
        didSet {
            self.configure()
        }
    }
    private let lab1 = UILabel()
    private let lab2 = UILabel()
    private let lab3 = UILabel()
    private let lab4 = UILabel()
    init(configuration: UIContentConfiguration) {
        self.configuration = configuration
        super.init(frame: .zero)
        // ... configure the subviews ...
        // ... and add them as subviews to self ...
        self.configure()
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    private func configure() {
        guard let config = self.configuration as? Configuration else { return }
        self.lab1.text = config.text1
        self.lab2.text = config.text2
        self.lab3.text = config.text3
        self.lab4.text = config.text4
    }
}
您可以看到该体系结构的要点。如果在将来的某个时候,我们被分配了一个新的
配置
,我们只需调用
配置
,即可再次设置标签的文本,而无需重新构建子视图本身。在现实生活中,我们可以通过检查传入的配置来获得更高的效率;如果与当前配置相同,则无需再次调用
self.configure()

结果是,我们现在可以在
表视图(u:cellForRowAt:)
实现中这样讨论:

override func tableView(_ tableView: UITableView, 
    cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(
            withIdentifier: self.cellID, for: indexPath) as! MyCell
        let config = MyCell.Configuration(
            text1: "Harpo",
            text2: "Groucho",
            text3: "Chico",
            text4: "Zeppo"
        )
        cell.contentConfiguration = config
        return cell
}
所有这些都非常聪明,但不幸的是,内容视图接口似乎必须在代码中创建-我们不能从nib加载现成的单元格,因为从nib加载的内容视图及其所有子视图将被从
makeContentView
实现返回的内容视图所取代。因此,苹果的配置架构不能与您在故事板或.xib文件中设计的单元一起使用。这很遗憾,但我看不出有什么办法可以解决。

从Xcode 12到iOS 14 表视图单元格配置:

struct CityCellConfiguration: UIContentConfiguration, Hashable {
var image: UIImage? = nil
var cityName: String? = nil
var fafourited: Bool? = false

func makeContentView() -> UIView & UIContentView {
    return CustomContentView(configuration: self)
}

func updated(for state: UIConfigurationState) -> Self {
    guard let state = state as? UICellConfigurationState else { return self }
    let updatedConfig = self

    return updatedConfig
}}
private func apply(configuration: CityCellConfiguration) {
    guard appliedConfiguration != configuration else { return }
    appliedConfiguration = configuration
    
    imageView.isHidden = configuration.image == nil
    imageView.image = configuration.image
    textLabel.isHidden = configuration.cityName == nil
    textLabel.text = configuration.cityName
    favouriteButton.isFavourited = configuration.fafourited ?? false
}
应用配置:

struct CityCellConfiguration: UIContentConfiguration, Hashable {
var image: UIImage? = nil
var cityName: String? = nil
var fafourited: Bool? = false

func makeContentView() -> UIView & UIContentView {
    return CustomContentView(configuration: self)
}

func updated(for state: UIConfigurationState) -> Self {
    guard let state = state as? UICellConfigurationState else { return self }
    let updatedConfig = self

    return updatedConfig
}}
private func apply(configuration: CityCellConfiguration) {
    guard appliedConfiguration != configuration else { return }
    appliedConfiguration = configuration
    
    imageView.isHidden = configuration.image == nil
    imageView.image = configuration.image
    textLabel.isHidden = configuration.cityName == nil
    textLabel.text = configuration.cityName
    favouriteButton.isFavourited = configuration.fafourited ?? false
}
更新单元内的配置:

覆盖函数更新配置(使用状态:UICellConfigurationState){
var content=CityCellConfiguration()。已更新(for:state)

content.image="最新版本的包含了一个如何开始自定义内容配置的示例。@smileyborg确实如此,我的回答也是如此。我想说的是,这应该在视频中出现。就像在UISplitViewController视频中一样,他们径直走到有趣、重要的部分,然后突然又离开了它在中,没有解释。为什么需要MyCell作为自定义单元格?是否可以为未连接的多个项目使用一个单元格?正如您所指出的,ContentConfiguration是内容视图的数据源,因此,对于不同的项目,我们只需要不同的内容视图。是否需要d