SwiftUI:创建自己的 TextField 并以编程方式更改内容
Posted
技术标签:
【中文标题】SwiftUI:创建自己的 TextField 并以编程方式更改内容【英文标题】:SwiftUI: Create own TextField and change the content programmatically 【发布时间】:2021-01-30 16:01:47 【问题描述】:我使用以下教程创建了自己的 TextField:https://www.youtube.com/watch?v=9kfbJVqqTKc&t=17s。一切正常,但我添加了一个功能来刷新 TextField 的内容。问题是当我以编程方式设置内容时,协调器中没有调用函数 textViewDidChange() 。这会导致整个 TextField 崩溃,这意味着当我键入内容时占位符不再消失并且它不会自动变大。当您到达应该创建新行的位置时,无论出于何种原因,文本都会被简单地删除。
有没有办法解决这个问题?
代码:
import SwiftUI
struct CustomTextField: View
var title: String
@Binding var text: String
var isFocused: Binding<Bool>?
@State var height: CGFloat = 20
var onCommit: (() -> ())?
init(_ title: String, text: Binding <String>, isFocused: Binding<Bool>? = nil, onCommit: (() -> ())? = nil)
self.title = title
self._text = text
self.isFocused = isFocused
self.onCommit = onCommit
var body: some View
ZStack(alignment: .topLeading)
Text(title)
.foregroundColor(Color.secondary.opacity(text.isEmpty ? 0.5 : 0))
.animation(nil)
CustomTextFieldRep(text: $text, isFocused: isFocused, height: $height, onCommit: onCommit)
.frame(height: height)
struct CustomTextFieldRep: UIViewRepresentable
@Binding var text: String
var isFocused: Binding<Bool>?
@Binding var height: CGFloat
var onCommit: (() -> ())?
func makeUIView(context: Context) -> UITextView
let uiView = UITextView()
uiView.font = UIFont.preferredFont(forTextStyle: .body)
uiView.backgroundColor = .clear
uiView.text = text
uiView.delegate = context.coordinator
uiView.textContainerInset = .zero
uiView.textContainer.lineFragmentPadding = 0
return uiView
func updateUIView(_ uiView: UITextView, context: Context)
if uiView.text != text
uiView.text = text
let size = uiView.sizeThatFits(CGSize(width: uiView.frame.width, height: CGFloat.greatestFiniteMagnitude))
height = size.height
if let isFocused = isFocused?.wrappedValue
if isFocused && !uiView.isFirstResponder
uiView.becomeFirstResponder()
else if !isFocused && uiView.isFirstResponder
uiView.resignFirstResponder()
func makeCoordinator() -> Coordinator
Coordinator(rep: self)
class Coordinator: NSObject, UITextViewDelegate
var rep: CustomTextFieldRep
internal init(rep: CustomTextFieldRep)
self.rep = rep
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool
if let onCommit = rep.onCommit, text == "\n"
onCommit()
return false
return true
func textViewDidChange(_ textView: UITextView)
rep.text = textView.text
let size = textView.sizeThatFits(CGSize(width: textView.frame.width, height: CGFloat.greatestFiniteMagnitude))
rep.height = size.height
func textViewDidBeginEditing(_ textView: UITextView)
rep.isFocused?.wrappedValue = true
func textViewDidEndEditing(_ textView: UITextView)
rep.isFocused?.wrappedValue = false
我认为如果我在协调器本身中调用 textViewDidChange() 函数,问题就可以解决。但是,我不知道该怎么做。
提前致谢
编辑: 我是如何实现自定义 TextField 的:
struct View: View
@ObservedObject private var addUebungVM = AddÜbungViewModel()
enum Focus
case name, beschreibung
@State var focus: Focus? = .name
var nameFocusBinding: Binding<Bool>
$focus.isEqual(to: .name)
var beschreibungFocusBinding: Binding<Bool>
$focus.isEqual(to: .beschreibung)
var body: some View
CustomTextField(placeholderName, text: $addUebungVM.übungName, isFocused: nameFocusBinding, onCommit: saveNewÜbung)
.alignmentNewExercise()
.styleTextField()
private func saveNewÜbung()
if !addUebungVM.übungName.isEmpty
DispatchQueue.main.async
addUebungVM.übungName = " "
addUebungVM.übungBeschreibung = " "
placeholderName = NSLocalizedString("nächsteÜbungString", comment: "")
focus = .name
编辑 2: 我想我发现了:
当视图第一次出现时:
-一切都很好
第一次重置后...
-
当我通过键盘按钮“返回”调用第二个重置时,它在文本不超过正常行时起作用,但是当我调用
通过“正常”按钮重置它根本不起作用
占位符不再显示
当我输入的文本比正常行长并且文本框应该变大时,文本会丢失
【问题讨论】:
这是否回答了您的问题***.com/a/58639072/12299030? @Asperi 不幸的是没有。当我使用您的变体时,同样的问题仍然存在 【参考方案1】:我正在使用您的代码并通过如下状态变量刷新内容:
struct ContentView: View
@State var text = ""
@State var isFocused = true
var body: some View
CustomTextField("Initial text", text: $text, isFocused: $isFocused)
print("done")
let t = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: t)
text = "Changed text"
这是解决您问题的方法吗?
【讨论】:
硬编码延迟不是很好的做法 @Subha_26 它以某种方式工作。我现在可以按下重置按钮并再次输入一些内容。但是,如果我已经删除了一次内容,然后再次输入内容并退出文本字段,则内容将自动删除。你知道为什么吗? @aheze 这样做只是为了对 TextField 的内容进行编程更改。实际上,这会在某些操作或 API 响应时触发。 还有一件事:当我以编程方式更改文本时,占位符不再可见。 @Subha_26 啊我明白了以上是关于SwiftUI:创建自己的 TextField 并以编程方式更改内容的主要内容,如果未能解决你的问题,请参考以下文章
使用 SwiftUI 启动 TextField 时出现 VStack 错误
如何创建只接受数字和单个点的 SwiftUI TextField?
UIPickerView 作为 SwiftUI 中 TextField() 的输入
检测用户何时停止/暂停在 TextField 中写入 - SwiftUI