首页 > 解决方案 > 添加到 UITableViewController 时,SwiftUI 视图大小被破坏

问题描述

我需要在现有UITableViewControllertableHeaderView. 但是,似乎 SwiftUI 视图的大小在添加到UITableViewController.

UIView如果我只是使用 a将我的 SwiftUI 视图转换为aUIHostingController并将其设置为tableHeaderView,则视图将显示在屏幕外:

func addHeaderView() {
    let view = VerticalTextStack()
    let hostingController = UIHostingController(rootView: view)
    tableView.tableHeaderView = hostingController.view
}

布局不正确

为了解决这个问题,我尝试了几种不同的方法来修复视图的高度。添加一个NSLayoutConstraint没有做任何事情。手动设置时tableHeaderView.frame.size,结果更好,因为至少现在视图显示在屏幕上,但多行Text变为单行并被截断。

正如您在此处看到的,第二个Text被截断:

截断的文本

这是一个展示问题的简化示例:

/// `UITableViewController` displaying a `UIView` as its `tableHeaderView`
class TableViewController: UITableViewController {
    let cellReuseIdentifier = "cell"
    let data = ["A", "B", "C", "D", "E"]
    let themeManager = AppThemeManager()

    // MARK: - UIViewController lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellReuseIdentifier)
        addHeaderView()
    }

    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()

        fixTableHeaderViewSize()
    }

    // MARK: - UITableViewDelegate
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        data.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier, for: indexPath)
        cell.textLabel?.text = data[indexPath.row]
        return cell
    }

    // MARK: - SwiftUI view
    func fixTableHeaderViewSize() {
        guard let tableHeaderView = tableView?.tableHeaderView else { return }
        let expectedHeight = tableHeaderView.systemLayoutSizeFitting(UIView.layoutFittingExpandedSize).height
        let expectedSize = CGSize(width: tableHeaderView.frame.width, height: expectedHeight)

        tableHeaderView.frame.size = expectedSize
    }

    func addHeaderView() {
        let view = VerticalTextStack()
        let hostingController = UIHostingController(rootView: view)
        tableView.tableHeaderView = hostingController.view
    }
}

private struct VerticalTextStack: View {
    let data = ["First", "I am a very long text that only fits in multiple lines. I still continue.", "Third"]
    let themeManager = AppThemeManager()

    var body: some View {
        VStack(spacing: 10) {
            ForEach(data, id: \.self) { value in
                Text(value)
            }
        }
    }
}

我也尝试过转移addHeaderView到其他 UIViewController 函数,例如viewWillLayoutSubviews,但这并没有改变任何东西。

在内部设置lineLimitnil或任何大的数字并添加到也不会产生多行。TextVerticalTextStack.layoutPriority(.greatestFiniteMagnitude)TextText

标签: swiftuitableviewswiftuiuikit

解决方案


这是一个可能的解决方案。

使用此更改您的添加标题视图功能。

func addHeaderView() {
    
    let view = VerticalTextStack()
    let hostingController = UIHostingController(rootView: view)
    
    let headerViewMain = UIView()
    headerViewMain.backgroundColor = .red
    headerViewMain.addSubview(hostingController.view)
    
    hostingController.view.translatesAutoresizingMaskIntoConstraints = false
    
    let constraints = [
        hostingController.view.topAnchor.constraint(equalTo: headerViewMain.topAnchor),
        hostingController.view.leftAnchor.constraint(equalTo: headerViewMain.leftAnchor),
        headerViewMain.bottomAnchor.constraint(equalTo: hostingController.view.bottomAnchor),
        headerViewMain.rightAnchor.constraint(equalTo: hostingController.view.rightAnchor)
    ]
    
    NSLayoutConstraint.activate(constraints)
    
    headerViewMain.frame.size.height = headerViewMain.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
    headerViewMain.frame.size.width = headerViewMain.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).width
    self.tableHeaderView = headerViewMain
    
    self.layoutIfNeeded()
    self.setNeedsLayout()
    
    self.reloadData()
}

推荐阅读