The content of UIHostingController has a weird offset when it is placed in each uitableviewcell

42 views Asked by At

I need to use uitableview to draw a message list. expected list In each tableviewcell, I use UIHostingController to load swiftui view. I found that when the page scrolls (and the cell is reused), there will be a werid offset. I used tableView.contentInsetAdjustmentBehavior = .scrollableAxes or automatic and it returned to normal, but when I tried to add any uiview under this tableview, the problem occurred again. werid offset in each cell enter image description here a simple demo code:

import SwiftUI
import Combine

struct DemoView: View {
    let height : CGFloat
    var body: some View {
        ZStack(alignment: .top, content: {
            Color.random
            Text("RowHeight:\(height)")
            ZStack(alignment: .bottom) {
                Color.clear
                Text("Bottom")
            }
        })
        .frame(height: height)
    }
}

class DemoTableView : UIViewController, UITableViewDelegate, UITableViewDataSource {
    let ROW_COUNT = 20
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        ROW_COUNT
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return CGFloat(50 + indexPath.row*5)
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if let cell = tableView.dequeueReusableCell(withIdentifier: "cell") {
            cell.contentView.subviews.forEach{ $0.removeFromSuperview() }
            
            let ht = self.tableView(tableView, heightForRowAt: indexPath)
            let view = DemoView(height: ht)
            let host = UIHostingController(rootView: view)
            cell.contentView.place(host.view) { v, ly in
                ly.inset = .zero
            }
            self.addChild(host)
            host.didMove(toParent: self)
            host.view.invalidateIntrinsicContentSize()
            return cell
        }
        return .init(style: .default, reuseIdentifier: "cell")
    }
    override func viewDidAppear(_ animated: Bool) {
        
        super.viewDidAppear(animated)
        
        self.view.backgroundColor = .white

//HERE: I tried to add any uiview under this tableview, then the problem occurred again
        self.view.addSubview(UIView())
        
        let tableView = UITableView(frame: self.view.bounds, style: .plain)

//both autoresize & autolayout has the same question
//        self.view.addSubview(tableView)
//        tableView.frame = self.view.bounds
//        tableView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        tableView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(tableView)
        NSLayoutConstraint.activate([
//            tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
//            tableView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor),
//            tableView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor),
//            tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
            tableView.topAnchor.constraint(equalTo: view.topAnchor),
            tableView.leftAnchor.constraint(equalTo: view.leftAnchor),
            tableView.rightAnchor.constraint(equalTo: view.rightAnchor),
            tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
        
        tableView.delegate = self
        tableView.dataSource = self
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        tableView.separatorStyle = .none
        tableView.contentInsetAdjustmentBehavior = .scrollableAxes
        
    }
}

struct DemoPage : UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> some UIViewController {
        return DemoTableView()
    }
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
        
    }
}

#Preview {
    DemoPage().ignoresSafeArea()
}

I would like to ask if this is a bug in iOS's bridging between uikit and swiftui. Currently, my project uses swiftui to draw each cell, but uitableview is needed to accurately control the scrolling state (swiftui is very troublesome to deal with). In addition, I need to support iOS15, so I cannot use UIHostingConfiguration. Is it a reliable and mature solution to use uitableviewcell to nest uihostingcontroller?

0

There are 0 answers