问题描述
我需要在现有的 UITableViewController
中显示一个 SwiftUI 视图,作为 tableHeaderView
。但是,当将 SwiftUI 视图添加到 UITableViewController
时,它的大小似乎被破坏了。
如果我只是使用 UIView
将我的 SwiftUI 视图转换为 UIHostingController
并将其设置为 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
,但这没有任何改变。
将 lineLimit
设置为 nil
或 Text
内的 VerticalTextStack
上的任何大数并将 .layoutPriority(.greatestFiniteMagnitude)
添加到 Text
都不会使Text
也可以是多行。
解决方法
这是一个可能的解决方案。
使用此更改添加标题视图功能。
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()
}