具有自定义配置的 UICollectionView 列表 - 如何将单元格中的更改传递到视图控制器?

2024-04-06

我已经实现了UICollectionView自定义列表UICollectionViewCell and UIContentConfiguration使用新的iOS 14API。我一直在关注这个教程:https://swiftsenpai.com/development/uicollectionview-list-custom-cell/ https://swiftsenpai.com/development/uicollectionview-list-custom-cell/(以及 Apple 的示例项目)

基本上你现在有一个UICollectionViewCell, a UIContentConfiguration and a UIContentView. The cell只是设置其配置,content configuration保存单元格的数据及其所有可能的状态,并且content view是实际的UIView取代UICollectionViewCell.contentView.

我已经让它工作了,它非常棒而且干净。但有一点我不明白:

您将如何添加回调UIContentView,或者传达单元格中发生的变化的东西(UISwitch切换或UITextField例如)更改为viewController?之间唯一的联系viewController创建时单元格位于单元格注册内collectionView的数据来源:

// Cell
class Cell: UICollectionViewListCell {
    
    var event: Event?
    var onEventDidChange: ((_ event: Event) -> Void)?
    //...
}


// Example cell registration in ViewController
let eventCellRegistration = UICollectionView.CellRegistration<Event.Cell, Event> { [weak self] (cell, indexPath, event) in
    cell.event = event // Setting the data model for the cell
    // This is what I tried to do. A closure that the cell calls, whenever the cell made changes to the event (the model)
    cell.onEventDidChange = { event in /* update database */ }
}

这是我能想到的唯一可以放置此类连接的地方,如上面的示例所示。然而,这不起作用,因为单元格不再对其内容负责。此关闭必须传递给UIContentView这正在为单元格创建实际的视图。

单元格与其内容视图之间的唯一联系是内容配置,但不能将闭包作为属性,因为它们不相等。所以我无法建立连接。

有谁知道如何做到这一点?

Thanks!


如果您编写自己的配置,则您负责其属性。因此,让您的配置定义一个协议并给它一个delegate财产!单元格注册对象将视图控制器(或任何人)设置为配置的委托。内容视图配置 UISwitch 或向其发送信号的任何内容,内容视图将该信号传递给配置的委托。

一个工作示例

这是complete工作示例的代码。我选择使用表视图而不是集合视图,但这完全无关;内容配置适用于两者。

您需要做的就是将表视图放入视图控制器中,使视图控制器成为表视图的数据源,并使表视图成为视图控制器的数据源。tableView.

extension UIResponder {
    func next<T:UIResponder>(ofType: T.Type) -> T? {
        let r = self.next
        if let r = r as? T ?? r?.next(ofType: T.self) {
            return r
        } else {
            return nil
        }
    }
}
protocol SwitchListener : AnyObject {
    func switchChangedTo(_:Bool, sender:UIView)
}
class MyContentView : UIView, UIContentView {
    var configuration: UIContentConfiguration {
        didSet {
            config()
        }
    }
    let sw = UISwitch()
    init(configuration: UIContentConfiguration) {
        self.configuration = configuration
        super.init(frame:.zero)
        sw.translatesAutoresizingMaskIntoConstraints = true
        self.addSubview(sw)
        sw.center = CGPoint(x:self.bounds.midX, y:self.bounds.midY)
        sw.autoresizingMask = [.flexibleTopMargin, .flexibleBottomMargin, .flexibleLeftMargin, .flexibleRightMargin]
        sw.addAction(UIAction {[unowned sw] action in
            (configuration as? Config)?.delegate?.switchChangedTo(sw.isOn, sender:self)
        }, for: .valueChanged)
        config()
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    func config() {
        self.sw.isOn = (configuration as? Config)?.isOn ?? false
    }
}
struct Config: UIContentConfiguration {
    var isOn = false
    weak var delegate : SwitchListener?
    func makeContentView() -> UIView & UIContentView {
        return MyContentView(configuration:self)
    }
    func updated(for state: UIConfigurationState) -> Config {
        return self
    }
}
class ViewController: UIViewController, UITableViewDataSource {
    @IBOutlet var tableView : UITableView!
    var list = Array(repeating: false, count: 100)
    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.list.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        var config = Config()
        config.isOn = list[indexPath.row]
        config.delegate = self
        cell.contentConfiguration = config
        return cell
    }
}
extension ViewController : SwitchListener {
    func switchChangedTo(_ newValue: Bool, sender: UIView) {
        if let cell = sender.next(ofType: UITableViewCell.self) {
            if let ip = self.tableView.indexPath(for: cell) {
                self.list[ip.row] = newValue
            }
        }
    }
}

该示例的关键部分

好吧,它可能看起来很多,但它主要是任何具有自定义内容配置的表视图的纯样板。唯一有趣的部分是 SwitchListener 协议及其实现,以及addAction内容视图初始化程序中的行;这就是这个答案第一段描述的内容。

因此,在内容视图的初始值设定项中:

sw.addAction(UIAction {[unowned sw] action in
    (configuration as? Config)?.delegate?.switchChangedTo(sw.isOn, sender:self)
}, for: .valueChanged)

在扩展中,响应该调用的方法:

func switchChangedTo(_ newValue: Bool, sender: UIView) {
    if let cell = sender.next(ofType: UITableViewCell.self) {
        if let ip = self.tableView.indexPath(for: cell) {
            self.list[ip.row] = newValue
        }
    }
}

另一种方法

这个答案仍然使用协议和委托架构,OP 宁愿不这样做。现代的方法是提供一个属性,其值是一个可以调用的函数directly.

因此,我们没有给我们的配置一个委托,而是给它一个回调属性:

struct Config: UIContentConfiguration {
    var isOn = false
    var isOnChanged : ((Bool, UIView) -> Void)?

内容视图的初始化程序配置界面元素,以便当它发出信号时,isOnChanged函数被称为:

sw.addAction(UIAction {[unowned sw] action in
    (configuration as? Config)?.isOnChanged?(sw.isOn, self)
}, for: .valueChanged)

它仍然只是为了显示什么isOnChanged功能is。在我的示例中,它与之前架构中的委托方法完全相同。因此,当我们配置单元格时:

config.isOn = list[indexPath.row]
config.isOnChanged = { [weak self] isOn, v in
    if let cell = v.next(ofType: UITableViewCell.self) {
        if let ip = self?.tableView.indexPath(for: cell) {
            self?.list[ip.row] = isOn
        }
    }
}

cell.contentConfiguration = config
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

具有自定义配置的 UICollectionView 列表 - 如何将单元格中的更改传递到视图控制器? 的相关文章

  • 避免 UIImage 的 imageNamed - 内存管理

    我正在经历这个链接 http akosma com 2009 01 28 10 iphone memory management tips 我遇到了一个点避免 UIImage 的 imageNamed 出于什么原因我们应该避免这种情况 它会
  • UIWebView Bug:-[UIWebView cut:]:无法识别的选择器发送到实例

    In the UIWebView 如果包含文本的输入元素具有焦点 并且按下按钮导致输入失去焦点 则随后双击输入以重新获得焦点并从出现的弹出栏中选择 剪切 或 复制 或 粘贴 会导致这UIWebView因错误而崩溃 UIWebView cut
  • 如何反转 CGPath 的点顺序

    我想画一个圆圈 并用它打出字母 为此 我需要顺时针抚摸圆圈 逆时针抚摸字母 这一切都很好 但是当我使用 Core Text 获取字母路径时 我不知道如何从本质上反转该路径 不是镜像或旋转或任何东西 这很简单 我希望点笔画顺序是逆时针的 这实
  • 分发内部业务 IOS 应用程序

    我遇到了 IOS 应用程序分发的一个令人困惑的部分 因此 我需要简单细分一下我的限制 即仅将我的应用程序分发给我的员工 同事或任何被视为 内部 的人 这是表明我不希望该应用程序出现在应用程序商店中的另一种方式 我的情况是我为几家公司开发 他
  • Swift 中的 UIAlert 自动消失?

    我有以下代码 Creates Alerts on screen for user func notifyUser title String message String gt Void let alert UIAlertController
  • 苹果推送通知在生产中不起作用

    我们完全陷入困境 请帮忙 我和我的团队制作了一个 iPhone 应用程序 这是我们第一次在 iOS 上尝试 一切都很好 直到我们提交应用程序并在应用程序商店上可用为止 推送通知服务无法正常工作 我在网上搜索并尝试根据人们的建议仔细检查我们的
  • CGPoint 标量乘法 Swift

    我正在 SpriteKit 中构建一个平台游戏 并将为我的实体实现更新功能 以便它们根据重力和速度移动 但是 我需要使添加的速度量与增量时间成比例 以防止帧速率影响我的实体的移动方式 因此我将导入 GLKit 以便我可以使用标量函数 但是
  • 使用 UISearchBar 过滤数组

    我目前正在使用以下代码来过滤数组并将结果显示在我的 tableView 中 问题是 只有当搜索与确切的单词匹配时 才会返回结果 如何更改数组过滤器以在输入时搜索每个字符 let data Mango Grape Berry Orange A
  • 使用 Simulator 时 Xcode 10 中的屏幕截图尺寸错误

    我正在尝试使用 Xcode 10 模拟器为 iTunes 制作屏幕截图 但图像大小错误 我读过Debug gt Optimize Rendering for Window Scale会有帮助 但在 Xcode 中没有这样的选项 有人有这个问
  • 相当于 Interface Builder 中 UIButton 的动态类型“自动调整字体”设置?

    UILabel 有一个Dynamic Type Automatically Adjusts FontInterface Builder 属性检查器中的复选框 Interface Builder 中是否有等效项用于自动调整 UIButton
  • 径向渐变绘制性能 - OpenGL-ES 可以改进吗?

    我正在开发一个图像处理应用程序 它将径向渐变叠加在从照片库加载的图像上 在屏幕上 我有一个滑块可以动态地增大 减小径向渐变的半径 我发现模拟器上的性能很好 但在 iPhone 3G 或 3GS 上就很糟糕了much移动滑块时重绘速度较慢 我
  • 获取对 iOS 应用程序中最顶层视图/窗口的引用

    我正在创建一个可重用的框架 用于在 iOS 应用程序中显示通知 我希望将通知视图添加到应用程序中其他所有内容的顶部 有点像 UIAlertView 当我初始化监听 NSNotification 事件并添加视图作为响应的管理器时 我需要获取对
  • 两者都实现了类。将使用两者之一

    我有一个项目 它具有使用 SocketRocket 的依赖项 通过 CocoaPods 安装 并从 HeapAnalytics 导入了静态库 显然 HeapAnalytics 库已经使用了 SocketRocket 编译时没有出现错误 但在
  • 如何自动缩放mapView以显示叠加层

    我可以在 mapView 上绘制多边形 但是我需要找到多边形并手动缩放它 有没有办法自动执行此过程 例如调整中心多边形 我浏览过互联网并阅读了一些相关文章 其中大多数都是基于折线和点的 任何形式的帮助将不胜感激 因为我正在寻找解决方案一段时
  • 多次添加同一个子视图来查看

    我不知道这是否可行 但我想做的是将子视图多次添加到视图中 我尝试过这样的事情 self view addSubview newView newView center CGPointMake 160 100 self view addSubv
  • “同时创建 xib 文件”按钮已禁用

    我在创建时遇到这个问题UIView s子类 创建 例如 UIViewControllers or UITableViewCells没关系 为什么会出现这种情况 I create view using cmd N and Xcode Vers
  • iOS - NSNotificationCenter 多个UIKeyboard通知

    我有两个视图控制器 我们称它们为 A 和 B 1 在 A 中 我显示一个包含文本字段的 popOver 2 B中有一个UITextView用于简单的文本编辑 我必须管理 A 和 B 中的键盘才能滚动键盘隐藏的内容 我知道如何重新定位内容 我
  • 在 iOS 11 中创建 Gif 图像颜色贴图

    最近 我在创建 Gif 时遇到了一个问题 如果它太大 颜色就会丢失 然而 感谢 SO 的帮助 有人能够帮助我找到解决方法并创建我自己的颜色图 上一个问题在这里 保存动画 Gif 时 iOS 颜色不正确 https stackoverflow
  • 是什么导致了这个 iPhone 崩溃日志?

    我有点卡住了 需要解决这个问题 因为我的一个应用程序出现了随机崩溃 而这些崩溃并不总是能够重现 这是崩溃日志之一 Incident Identifier 59865612 9F00 44EA 9474 2BF607AD662E CrashR
  • iOS 10 的错误? NSDate 日本地区时间描述和 24 小时休息

    这似乎是 iOS 10 的一个错误 在 iOS 8 和 9 中都可以 NSDate date description 的小时描述是错误的 它附加了 24 小时描述和 12 小时描述 我没有使用 NSDateFormatter 只是默认设置

随机推荐