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

SwiftUI笔记视图:TextEditor内部滚动边距设置(避免文本裁剪)

解决TextEditor悬浮Footer下的滚动底部空间问题

针对你遇到的问题,核心是要给TextEditor的滚动内容添加底部额外空间,而非给视图本身加padding,这样就能让文本滚动到Footer下方且完整显示,无需手动添加换行符。

iOS 16+ 简洁方案

利用SwiftUI 3.0新增的scrollContentInsets修饰符,直接给滚动内容设置底部插入值,数值可根据Footer高度或你想要的5个换行高度调整:

var body: some View {
    ZStack(alignment: .bottom) {
        VStack(alignment: .leading) {
            Text("\(note.date.formatted())")
                .padding([.leading, .trailing])
                
            TextEditor(text: $note.text)
                .padding()
                // 设置滚动内容的底部插入,可替换为字体行高×5的计算值
                .scrollContentInsets(.init(top: 0, leading: 0, bottom: 150, trailing: 0))
        }
        
        Footer {}
    }
}

如果要精确匹配5个换行的高度,可先计算字体行高:

// 在视图内定义计算属性
private var bottomInset: CGFloat {
    let lineHeight = UIFont.preferredFont(forTextStyle: .body).lineHeight
    return lineHeight * 5
}

// 替换到scrollContentInsets中使用
.scrollContentInsets(.init(top: 0, leading: 0, bottom: bottomInset, trailing: 0))

iOS 15及以下兼容方案

针对更低版本iOS,需要通过UIViewRepresentable包装原生UITextView,设置其contentInset属性:

struct CustomTextEditor: UIViewRepresentable {
    @Binding var text: String
    let bottomInset: CGFloat
    
    func makeUIView(context: Context) -> UITextView {
        let textView = UITextView()
        // 匹配SwiftUI默认字体样式
        textView.font = UIFont.preferredFont(forTextStyle: .body)
        // 设置内容底部插入
        textView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: bottomInset, right: 0)
        return textView
    }
    
    func updateUIView(_ uiView: UITextView, context: Context) {
        uiView.text = text
        uiView.delegate = context.coordinator
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, UITextViewDelegate {
        var parent: CustomTextEditor
        
        init(_ parent: CustomTextEditor) {
            self.parent = parent
        }
        
        func textViewDidChange(_ textView: UITextView) {
            parent.text = textView.text
        }
    }
}

// 替换原TextEditor使用
var body: some View {
    ZStack(alignment: .bottom) {
        VStack(alignment: .leading) {
            Text("\(note.date.formatted())")
                .padding([.leading, .trailing])
                
            CustomTextEditor(text: $note.text, bottomInset: UIFont.preferredFont(forTextStyle: .body).lineHeight * 5)
                .padding()
        }
        
        Footer {}
    }
}

为什么直接加padding不行?

.padding([.bottom], 150)是给TextEditor视图本身添加内边距,这会挤压文本的可编辑区域,导致文本显示空间变小出现裁剪;而scrollContentInsets或contentInset是给滚动内容添加额外的底部空白区域,文本可以滚动到该区域内,不会被裁剪,同时Footer悬浮在视图上层,文本能完整滚动到Footer下方。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 00:31:09