SwiftUI中UITextView无法自适应尺寸的问题求助
解决SwiftUI中嵌套ScrollView的HTML文本组件高度异常问题
问题背景
需在iOS14兼容环境下,用SwiftUI显示HTML内容,要求自定义字体与文本颜色,因此采用UITextView封装为UIViewRepresentable组件。但组件嵌套在ScrollView的VStack中时,出现以下问题:
- 初始实现中文本始终单行显示,无法垂直扩展
- 添加
setContentCompressionResistancePriority(.defaultLow, for: .horizontal)后高度显示正常,但竖屏时最后一行文本不可见,横屏无异常
解决方案
核心思路是让UITextView的尺寸计算与SwiftUI布局系统深度协同,避免手动设置frame干扰布局逻辑,同时针对ScrollView的无限空间特性调整视图优先级。
修改后的完整代码
struct HTMLTextView: UIViewRepresentable { private var htmlString: String private var font: UIFont = .systemFont(ofSize: 14) private var textColor: UIColor = .darkText init(htmlString: String) { self.htmlString = htmlString } func makeUIView(context: Context) -> UITextView { let textView = UITextView() textView.isScrollEnabled = false textView.isEditable = false textView.backgroundColor = .clear // 降低水平压缩优先级,允许SwiftUI约束宽度 textView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) // 提高垂直拥抱优先级,优先使用文本自然高度 textView.setContentHuggingPriority(.defaultHigh, for: .vertical) return textView } func updateUIView(_ textView: UITextView, context: Context) { textView.attributedText = buildAttributedString(fromHTML: htmlString) // 强制触发固有尺寸更新,确保内容变化时重新计算高度 textView.invalidateIntrinsicContentSize() } func font(_ font: UIFont) -> Self { var copy = self copy.font = font return copy } func textColor(_ textColor: UIColor) -> Self { var copy = self copy.textColor = textColor return copy } // MARK: - Private private func buildAttributedString(fromHTML htmlString: String) -> NSAttributedString { let htmlData = Data(htmlString.utf8) let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [ .documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue ] guard let attributedString = try? NSMutableAttributedString(data: htmlData, options: options, documentAttributes: nil) else { return NSAttributedString(string: "") } let range = NSRange(location: 0, length: attributedString.length) // 先移除HTML自带的字体属性,避免与自定义字体冲突 attributedString.removeAttribute(.font, range: range) attributedString.addAttributes([ .font: font, .foregroundColor: textColor ], range: range) return attributedString } }
调用方式
在ScrollView中使用时,通过SwiftUI的frame约束宽度,让组件自适应高度:
ScrollView { VStack(spacing: 16) { HTMLTextView(htmlString: "<p>这是一段多行HTML文本,测试换行与高度自适应</p><p>第二行内容,确保最后一行在竖屏时正常显示</p>") .font(.systemFont(ofSize: 15)) .textColor(.darkText) .frame(maxWidth: .infinity, alignment: .leading) .padding() // 其他视图... } }
关键修改说明
- 移除手动frame设置:依赖UITextView的
intrinsicContentSize让SwiftUI自动计算高度,避免布局冲突 - 调整视图优先级:通过
setContentHuggingPriority确保垂直方向优先使用文本自然高度,setContentCompressionResistancePriority允许SwiftUI约束水平宽度 - 优化HTML转富文本逻辑:先移除HTML自带的字体属性,避免自定义字体被覆盖
- 强制更新固有尺寸:在内容变化时调用
invalidateIntrinsicContentSize(),确保高度实时更新
内容的提问来源于stack exchange,提问作者Ievgen Leichenko
相关产品推荐
相关产品推荐

