SwiftUI:如何将 TextField 高度动态更改为阈值然后允许滚动?
SwiftUI: How to change the TextField height dynamicly to a threshold and then allow scrolling?
LineLimit 不起作用:
TextField("Text", text: $model.commitDescr)
.multilineTextAlignment(.leading)
.lineLimit(5)
LineLimit 没有任何改变 - 我能够显示 10-20-30 行。
与 scrollView 类似的方法总是用 maxHeight(400) 代替动态高度:
ScrollView() {
TextField("Text", text: $model.commitDescr)
.multilineTextAlignment(.leading)
.lineLimit(5)
}
.frame(minHeight: 20, maxHeight: 400)
以下也不能正常工作:
TextField("Text", text: $model.commitDescr)
.multilineTextAlignment(.leading)
.lineLimit(5)
.frame(minHeight: 20, maxHeight: 400)
通常,TextField
仅用于一行文本。
对于多行输入,TextEditor
可能是原生 SwiftUI
中更好的解决方案。你也可以为此设置一个.frame(maxHeight: XX, alignment: .leading)
。
需要说明的是,下面的示例将确保编辑器的高度始终为 200 点,即使没有输入文本也是如此:
TextEditor(text: $variable)
.frame(maxHeight: 200, alignment: .center)
根据提问者的要求,一个额外的例子,其中编辑器很小(50 点高)并且只在输入文本时扩展到 maxHeight:
TextEditor(text: $variable)
.frame(minHeight: 50, maxHeight: 200, alignment: .center)
@available(iOS 14.0, macOS 11.0, *)
使用 TextEditor 代替 TextField
TextEditor(text: $text)
.fixedSize(horizontal: false, vertical: true)
.multilineTextAlignment(.leading)
使用示例:
ScrollView {
VStack{
TextEditor(text: $text)
.frame(minHeight: 40, alignment: .leading)
.frame(maxHeight: MAX_HEIGHT)
.cornerRadius(10, antialiased: true)
.foregroundColor(.black)
.font(.body)
.padding()
.fixedSize(horizontal: false, vertical: true)
.multilineTextAlignment(.leading)
}
.background(Color.red)
}
固定高度,允许滚动
使用TextEditor
,而不是TextField
。然后,您可以将 maxHeight
设置为您想要的任何值。
struct ContentView: View {
@State private var text = ""
var body: some View {
TextEditor(text: $text)
.frame(maxHeight: 300)
}
}
结果:
固定行数,不滚动
如果你想用 TextEditor
限制你可以显示的行数,你可以使用 SwiftUI-Introspect 来做到这一点。
示例:
struct ContentView: View {
@State private var text = ""
var body: some View {
TextEditor(text: $text)
.introspectTextView { textView in
textView.textContainer.maximumNumberOfLines = 5
textView.textContainer.lineBreakMode = .byTruncatingTail
}
}
}
结果:
解决这个问题的方法如下:
struct ContentView: View {
@State private var commitDescr: String = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
var body: some View {
TextEditorView(string: $commitDescr)
}
}
struct TextEditorView: View {
@Binding var string: String
@State private var textEditorHeight : CGFloat = CGFloat()
var body: some View {
ZStack(alignment: .leading) {
Text(string)
.lineLimit(5)
.foregroundColor(.clear)
.padding(.top, 5.0)
.padding(.bottom, 7.0)
.background(GeometryReader {
Color.clear.preference(key: ViewHeightKey.self,
value: [=10=].frame(in: .local).size.height)
})
TextEditor(text: $string)
.frame(height: textEditorHeight)
}
.onPreferenceChange(ViewHeightKey.self) { textEditorHeight = [=10=] }
}
}
struct ViewHeightKey: PreferenceKey {
static var defaultValue: CGFloat { 0 }
static func reduce(value: inout Value, nextValue: () -> Value) {
value = value + nextValue()
}
}
LineLimit 不起作用:
TextField("Text", text: $model.commitDescr)
.multilineTextAlignment(.leading)
.lineLimit(5)
LineLimit 没有任何改变 - 我能够显示 10-20-30 行。
与 scrollView 类似的方法总是用 maxHeight(400) 代替动态高度:
ScrollView() {
TextField("Text", text: $model.commitDescr)
.multilineTextAlignment(.leading)
.lineLimit(5)
}
.frame(minHeight: 20, maxHeight: 400)
以下也不能正常工作:
TextField("Text", text: $model.commitDescr)
.multilineTextAlignment(.leading)
.lineLimit(5)
.frame(minHeight: 20, maxHeight: 400)
通常,TextField
仅用于一行文本。
对于多行输入,TextEditor
可能是原生 SwiftUI
中更好的解决方案。你也可以为此设置一个.frame(maxHeight: XX, alignment: .leading)
。
需要说明的是,下面的示例将确保编辑器的高度始终为 200 点,即使没有输入文本也是如此:
TextEditor(text: $variable)
.frame(maxHeight: 200, alignment: .center)
根据提问者的要求,一个额外的例子,其中编辑器很小(50 点高)并且只在输入文本时扩展到 maxHeight:
TextEditor(text: $variable)
.frame(minHeight: 50, maxHeight: 200, alignment: .center)
@available(iOS 14.0, macOS 11.0, *)
使用 TextEditor 代替 TextField
TextEditor(text: $text)
.fixedSize(horizontal: false, vertical: true)
.multilineTextAlignment(.leading)
使用示例:
ScrollView {
VStack{
TextEditor(text: $text)
.frame(minHeight: 40, alignment: .leading)
.frame(maxHeight: MAX_HEIGHT)
.cornerRadius(10, antialiased: true)
.foregroundColor(.black)
.font(.body)
.padding()
.fixedSize(horizontal: false, vertical: true)
.multilineTextAlignment(.leading)
}
.background(Color.red)
}
固定高度,允许滚动
使用TextEditor
,而不是TextField
。然后,您可以将 maxHeight
设置为您想要的任何值。
struct ContentView: View {
@State private var text = ""
var body: some View {
TextEditor(text: $text)
.frame(maxHeight: 300)
}
}
结果:
固定行数,不滚动
如果你想用 TextEditor
限制你可以显示的行数,你可以使用 SwiftUI-Introspect 来做到这一点。
示例:
struct ContentView: View {
@State private var text = ""
var body: some View {
TextEditor(text: $text)
.introspectTextView { textView in
textView.textContainer.maximumNumberOfLines = 5
textView.textContainer.lineBreakMode = .byTruncatingTail
}
}
}
结果:
解决这个问题的方法如下:
struct ContentView: View {
@State private var commitDescr: String = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
var body: some View {
TextEditorView(string: $commitDescr)
}
}
struct TextEditorView: View {
@Binding var string: String
@State private var textEditorHeight : CGFloat = CGFloat()
var body: some View {
ZStack(alignment: .leading) {
Text(string)
.lineLimit(5)
.foregroundColor(.clear)
.padding(.top, 5.0)
.padding(.bottom, 7.0)
.background(GeometryReader {
Color.clear.preference(key: ViewHeightKey.self,
value: [=10=].frame(in: .local).size.height)
})
TextEditor(text: $string)
.frame(height: textEditorHeight)
}
.onPreferenceChange(ViewHeightKey.self) { textEditorHeight = [=10=] }
}
}
struct ViewHeightKey: PreferenceKey {
static var defaultValue: CGFloat { 0 }
static func reduce(value: inout Value, nextValue: () -> Value) {
value = value + nextValue()
}
}