【问题标题】:UITableView with UIViewRepresentable in SwiftUISwiftUI 中带有 UIViewRepresentable 的 UITableView
【发布时间】:2020-05-09 21:05:44
【问题描述】:

我正在尝试在 SwiftUI 应用中使用 UITableView

struct UIList: UIViewRepresentable {

    var rows: [String]

    func makeUIView(context: Context) -> UITableView {
        let collectionView = UITableView(frame: .zero, style: .plain)
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        collectionView.dataSource = context.coordinator
        collectionView.delegate = context.coordinator
        collectionView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
        return collectionView
    }

    func updateUIView(_ uiView: UITableView, context: Context) {
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(rows: rows)
    }

    class Coordinator: NSObject, UITableViewDataSource, UITableViewDelegate {

        var rows: [String]

        init(rows: [String]) {
            self.rows = rows
        }

        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            self.rows.count
        }

        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

            let tableViewCell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) //as! AlbumPrivateCell

            let view = Text(rows[indexPath.row]).frame(height: 50).background(Color.blue)// UIFactory(appComponent:

            let controller = UIHostingController(rootView: view)

            let tableCellViewContent = controller.view!

            tableCellViewContent.translatesAutoresizingMaskIntoConstraints = false

            tableViewCell.contentView.addSubview(tableCellViewContent)

            tableCellViewContent.topAnchor.constraint(equalTo: tableViewCell.contentView.topAnchor).isActive = true
            tableCellViewContent.leftAnchor.constraint(equalTo: tableViewCell.contentView.leftAnchor).isActive = true
            tableCellViewContent.bottomAnchor.constraint(equalTo: tableViewCell.contentView.bottomAnchor).isActive = true
            tableCellViewContent.rightAnchor.constraint(equalTo: tableViewCell.contentView.rightAnchor).isActive = true


            return tableViewCell
        }
    }
}

当我快速滚动表格时,单元格内容会在每个单元格的顶部和底部随机填充,知道为什么会发生这种情况吗?

PS:我知道我可以使用List,我尝试使用UITableView,因为我必须添加多个滑动动作,但List 只允许一个滑动动作(删除)

【问题讨论】:

  • 填充与单元格中显示的字符串的宽度一致。替代解决方案可能是将 SwiftUI 视图嵌入到 GeometryReader 中,然后将该几何图形传递给 UIList。然后,相应地使用该值初始化您的协调器,并将您的单元格框架宽度设置为 geom.size.width。

标签: ios swift uitableview uikit swiftui


【解决方案1】:

我认为这是由于重复使用的表格视图单元损坏...(并且可能丢失了主机控制器,因为那里是在堆栈上创建的,而不是存储在任何地方)

请在下面找到通过提到的修复更正了您的代码。使用 Xcode 11.2 / iOS 13.2 测试和使用。

这是代码(内联一些 cmets):

class HostingCell: UITableViewCell { // just to hold hosting controller
    var host: UIHostingController<AnyView>?
}

struct UIList: UIViewRepresentable {

    var rows: [String]

    func makeUIView(context: Context) -> UITableView {
        let collectionView = UITableView(frame: .zero, style: .plain)
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        collectionView.dataSource = context.coordinator
        collectionView.delegate = context.coordinator
        collectionView.register(HostingCell.self, forCellReuseIdentifier: "Cell")
        return collectionView
    }

    func updateUIView(_ uiView: UITableView, context: Context) {
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(rows: rows)
    }

    class Coordinator: NSObject, UITableViewDataSource, UITableViewDelegate {

        var rows: [String]

        init(rows: [String]) {
            self.rows = rows
        }

        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            self.rows.count
        }

        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

            let tableViewCell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! HostingCell

            let view = Text(rows[indexPath.row])
                    .frame(height: 50).background(Color.blue)

            // create & setup hosting controller only once
            if tableViewCell.host == nil {
                let controller = UIHostingController(rootView: AnyView(view))
                tableViewCell.host = controller

                let tableCellViewContent = controller.view!
                tableCellViewContent.translatesAutoresizingMaskIntoConstraints = false
                tableViewCell.contentView.addSubview(tableCellViewContent)
                tableCellViewContent.topAnchor.constraint(equalTo: tableViewCell.contentView.topAnchor).isActive = true
                tableCellViewContent.leftAnchor.constraint(equalTo: tableViewCell.contentView.leftAnchor).isActive = true
                tableCellViewContent.bottomAnchor.constraint(equalTo: tableViewCell.contentView.bottomAnchor).isActive = true
                tableCellViewContent.rightAnchor.constraint(equalTo: tableViewCell.contentView.rightAnchor).isActive = true
            } else {
                // reused cell, so just set other SwiftUI root view
                tableViewCell.host?.rootView = AnyView(view)
            }
            tableViewCell.setNeedsLayout()
            return tableViewCell
        }
    }
}

UIList 本身添加了演示代码 - 也适用于专业模型。

struct TestUIList: View {
    var body: some View {
        UIList(rows: generateRows())
    }

    func generateRows() -> [String] {
        (0..<100).reduce([]) { $0 + ["Row \($1)"] }
    }
}

【讨论】:

  • @Pasta,填充已解决并经过测试,请参阅演示更新。
  • 嗨,我注意到大视图会被剪裁,例如如果文本很长,它会被剪掉。有什么解决办法吗?
  • @Asperi,你的代码几乎对我有用,除了 UITableView 一次只显示一个单元格。某处是否有 tableView 高度属性?
  • @Asperi,忘记我说的,你的代码按你说的工作。我的问题是我将 UIList 嵌入到表单的一个部分中。我必须给 UIList 一个足够宽和高的 .frame 才能显示多行。
猜你喜欢
  • 1970-01-01
  • 2021-09-30
  • 1970-01-01
  • 2020-05-07
  • 2022-01-18
  • 2022-01-22
  • 2022-12-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多