You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UITextView嵌套ScrollView时文本截断的SwiftUI技术问题

SwiftUI中ScrollView嵌套UITextView内容截断问题解决

问题现象

  • 在普通VStack中,文本可完整显示
  • 放入ScrollView后,文本较多时会被截断:UITextView布局尺寸正常(分隔线位置验证),但内容无法完全展示
  • 显式设置frame可解决内容截断,但需创建Binding,导致LazyVStack内的ScrollView出现抖动

原代码

SwiftUI主视图

var body: some View
{
    VStack
    {
        TextView(text: text)
        
        Rectangle().frame(height: 1).foregroundStyle(.red)
        
        ScrollView
        {
            TextView(text: text)
            
            Rectangle().frame(height: 1).foregroundStyle(.red)
        }
    }
    .padding(.horizontal)
}

UITextView封装视图

struct TextView: UIViewRepresentable {
let text: String

func makeUIView(context: Context) -> UITextView
{
    let textView = UITextView()
    textView.text = text
    
    textView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
    textView.isUserInteractionEnabled = true
    textView.isSelectable = true
    textView.isEditable = false
    textView.isScrollEnabled = false
    
    textView.backgroundColor = .clear
    textView.textContainer.lineFragmentPadding = 0
    textView.textContainerInset = .zero
    
    return textView
}

func updateUIView(_ textView: UITextView, context: Context) { }
}

解决方案

问题核心是ScrollView内部的UITextView未正确向SwiftUI报告自身内容高度,导致内容显示被截断。修改TextView代码,确保其正确计算并返回固有内容尺寸:

struct TextView: UIViewRepresentable {
    let text: String
    
    func makeUIView(context: Context) -> UITextView {
        let textView = UITextView()
        // 禁用自动布局转换,让SwiftUI管理约束
        textView.translatesAutoresizingMaskIntoConstraints = false
        
        textView.text = text
        textView.isUserInteractionEnabled = true
        textView.isSelectable = true
        textView.isEditable = false
        // 必须禁用滚动,让UITextView根据内容计算高度
        textView.isScrollEnabled = false
        
        textView.backgroundColor = .clear
        textView.textContainer.lineFragmentPadding = 0
        textView.textContainerInset = .zero
        
        // 设置垂直内容拥抱优先级,避免被压缩
        textView.setContentHuggingPriority(.defaultHigh, for: .vertical)
        return textView
    }
    
    func updateUIView(_ textView: UITextView, context: Context) {
        // 仅当文本变化时更新,避免不必要的刷新
        if textView.text != text {
            textView.text = text
            // 强制布局,确保固有尺寸更新
            textView.layoutIfNeeded()
        }
    }
}

关键修改点说明

  • 添加textView.translatesAutoresizingMaskIntoConstraints = false:让SwiftUI完全控制UITextView的布局约束,避免自动布局冲突
  • 设置垂直内容拥抱优先级为.defaultHigh:确保UITextView在ScrollView中不会被垂直方向压缩
  • 在updateUIView中更新文本后调用layoutIfNeeded():强制UITextView重新计算内容尺寸,确保固有内容高度正确传递给SwiftUI

这样修改后,ScrollView中的UITextView能完整展示全部文本,无需额外Binding,也不会导致LazyVStack内的抖动问题。

内容的提问来源于stack exchange,提问作者Khaled Sh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 14:05:15