次のチュートリアルで独自の 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:私が見つけたと思います:
ビューが初めて表示されるとき:
-すべてがうまく機能します
最初のリセット後...
- キーボードボタン「リターン」で2番目のリセットを呼び出すと、テキストが通常の行より長くない場合に機能しますが、「通常」ボタンでリセットを呼び出すとまったく機能しません
- プレースホルダーが表示されなくなりました
- 入力したテキストが通常の行よりも長くなり、テキスト ボックスを大きくする必要がある場合、テキストが失われます