添加到 UITableViewController 时,SwiftUI 视图大小被破坏
Posted
技术标签:
【中文标题】添加到 UITableViewController 时,SwiftUI 视图大小被破坏【英文标题】:SwiftUI view sizing is broken when added to UITableViewController 【发布时间】:2021-04-14 11:54:44 【问题描述】:我需要在现有的UITableViewController
中显示一个 SwiftUI 视图,如tableHeaderView
。但是,似乎 SwiftUI 视图的大小在添加到 UITableViewController
时被破坏了。
如果我只是使用 UIHostingController
将我的 SwiftUI 视图转换为 UIView
并将其设置为 tableHeaderView
,则视图将显示在屏幕外:
func addHeaderView()
let view = VerticalTextStack()
let hostingController = UIHostingController(rootView: view)
tableView.tableHeaderView = hostingController.view
Incorrect layout
为了解决这个问题,我尝试了几种不同的方法来修复视图的高度。添加NSLayoutConstraint
没有做任何事情。手动设置tableHeaderView.frame.size
时,结果更好,因为至少现在视图显示在屏幕上,但多行Text
s 变成单行并被截断。
正如您在此处看到的,第二个 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
或VerticalTextStack
内部Text
上的任何大数字并将.layoutPriority(.greatestFiniteMagnitude)
添加到Text
也不会使Text
成为多行。
【问题讨论】:
【参考方案1】:这是一个可能的解决方案。
用这个改变你的添加标题视图功能。
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()
【讨论】:
这段代码甚至无法编译,因为您似乎认为这是在UITableView
子类而不是UITableViewController
子类中。但是,即使我解决了这些问题,多行文本仍然是单行并被截断。你甚至测试过你提出的解决方案吗?顺便说一句,调用setNeedsLayout
之后 layoutIfNeeded
是一个可怕的想法,你为什么要在设置tableHeaderView
之后调用reloadData
?
第一个,我忘了这是 UITableViewController 类。是的,我测试了代码,它会在多行中产生问题,我认为在 layoutIfNeeded 之后调用 setNeedsLayout 并不可怕。并且对于重新加载,不调用也没关系。我使用了另一个现有的演示,所以为什么要重新加载代码。
和这一行解决的多行问题Text(value).frame(width: UIScreen.main.bounds.width).fixedSize().lineLimit(nil)
好吧,如果您的代码仍然存在多行文本问题,那么这完全可以解决我的问题吗?多行文本问题是我唯一无法解决的问题,所以这并不比我的原始代码好。调用setNeedsLayout
before layoutIfNeeded
可能有意义,但调用它之后根本没有意义。您首先告诉 UIKit 在必要时更新 UI,然后才告诉它有必要更新?
@DávidPásztor 检查我的第二条评论是否有多行文本问题。以上是关于添加到 UITableViewController 时,SwiftUI 视图大小被破坏的主要内容,如果未能解决你的问题,请参考以下文章
手动将 UITabBar 添加到 UITableViewController
从 UITableViewController 添加标记到 UIViewController
添加到 UITableViewController 时,SwiftUI 视图大小被破坏
将 UITableViewController 添加到其他视图
将 UINavigationBar 添加到没有 UINavigationController 的 UITableViewController