SwiftUI中如何实现TextEditor高度随内容动态自适应调整
实现方案
核心思路是通过隐藏的同步文本计算内容实际高度,动态绑定给TextEditor,同时限制最小高度保证至少显示1行内容,完整可运行代码如下:
import SwiftUI // 用于传递视图高度的PreferenceKey struct ViewHeightKey: PreferenceKey { static var defaultValue: CGFloat = 0 static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { value = nextValue() } } struct ContentView: View { @StateObject var textEditorReferenceType: TextEditorReferenceType = TextEditorReferenceType() var body: some View { Text("TextEditorView").bold().padding() VStack(spacing: 15) { ForEach($textEditorReferenceType.arrayOfString, id: \.self) { $string in TextEditorView(string: $string) } } .padding() } } struct TextEditorView: View { @Binding var string: String // 存储文本内容的实际高度 @State private var textHeight: CGFloat = 0 // 最小高度,可容纳1行文本,可根据需求调整 private let minHeight: CGFloat = 38 // 可选:设置最大高度,超过后内容变为滚动状态,不需要可删除该参数 private let maxHeight: CGFloat = 150 var body: some View { TextEditor(text: $string) .frame(minHeight: minHeight, maxHeight: max(maxHeight, textHeight)) .fixedSize(horizontal: false, vertical: true) .cornerRadius(10.0) .shadow(radius: 1.0) .background( // 用和TextEditor同配置的隐藏Text计算内容实际高度 Text(string) .font(.body) // 需和TextEditor的字体保持完全一致 .foregroundColor(.clear) .padding(4) // 对齐TextEditor的默认内边距,可根据实际样式调整 .frame(maxWidth: .infinity, alignment: .leading) .getViewHeight($textHeight) ) } } // 扩展View,添加读取高度的便捷方法 extension View { func getViewHeight(_ binding: Binding<CGFloat>) -> some View { self.background( GeometryReader { geo in Color.clear.preference(key: ViewHeightKey.self, value: geo.size.height) } ) .onPreferenceChange(ViewHeightKey.self) { value in binding.wrappedValue = value } } } class TextEditorReferenceType: ObservableObject { @Published var arrayOfString: [String] = ["Hello, World!", "Hello, World!", "Hello, World!"] }
实现说明
- 隐藏Text和TextEditor绑定同一份文本、使用相同字体配置,它的高度始终等于文本内容实际所需的高度
- 通过PreferenceKey将隐藏Text的高度同步给TextEditor的frame,实现高度随内容自适应
- minHeight参数保证TextEditor至少可以显示一行内容,maxHeight为可选配置,避免文本过多时控件占满整屏
- 如果自定义了TextEditor的字体、内边距,需要同步修改隐藏Text的对应配置,保证高度计算准确
内容的提问来源于stack exchange,提问作者swiftPunk
相关产品推荐
相关产品推荐

