带有 UIViewRepresantable 的 UITableView 的某些单元格定位错误

Some cells of UITableView with UIViewRepresantable are positioned wrong

我正在尝试将 UITableView 与 UIViewRepresantable 一起使用,它有点管用,但不是真的。有些行放置在错误的位置,要么与其他行重叠,要么添加了额外的填充。此外,即使我设置了 automaticDimension,它似乎也不会使行高适应行的内容。

这是演示:

代码如下:

import SwiftUI

struct ContentView: View {
    @State var rows : [String] = []
    var listData = ListData()
    
    var body: some View {
        VStack {
            Button(action: {
                self.getDataFromTheServer()
            }) {
               Text("Get 100 entries from the server")
            }
            UIList(rows: $rows)
        }
    }
    
    func getDataFromTheServer() {
        for _ in 1...100 {
            self.rows.append(self.listData.data)
            self.listData.data.append("a")
        }
    }

}

class ListData {
    var data: String = ""
}

class HostingCell: UITableViewCell {
    var host: UIHostingController<AnyView>?
}

struct UIList: UIViewRepresentable {

    @Binding var rows: [String]

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

    func updateUIView(_ uiView: UITableView, context: Context) {
        DispatchQueue.main.async {
            uiView.reloadData()
        }
    }

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

    class Coordinator: NSObject, UITableViewDataSource, UITableViewDelegate {

        @Binding var rows: [String]

        init(rows: Binding<[String]>) {
            self._rows = rows
        }

        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 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])
                    .background(Color.blue)
                    .lineLimit(nil)

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

                let tableCellViewContent = hostingController.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
        }
    }
}

UIHostingControllers 不能很好地调整自己的大小,我怀疑这是破坏自动布局的原因。尝试在设置控制器的 rootView 后添加:

hostingController.preferredContentSize = hostingController.sizeThatFits( )

就是说,您可能想完全避免使用 UIHostingController……如果您不厌其烦地使用 UITableView,为什么不在 UIKit 中也制作单元格呢?或者,如果您需要 SwiftUI 来处理行,为什么不使用 List 而不是托管 UITableView?

来自苹果:

感谢您的反馈,已记录。工程部门已确定目前没有解决此问题的计划。

我们建议使用 List,并针对 List 无法提供的任何需求提交单独的增强。