使用 UIViewRepresentable 在键盘上点击 return 按钮时应用程序冻结

App freezes when return button is tapped on keyboard with UIViewRepresentable

当我单击键盘上的 return 按钮时,应用程序冻结并且再也没有响应。我使用的是 UIViewRepresentable 而 return 是 UITextField 因为我无法使用 SwiftUI 在文本上创建轮廓。我 运行 在 Xcode beta 5 和 iPhone XR 模拟器上。

import SwiftUI
import UIKit

struct CustomTextField: View {
    @State var text: String
    @State var pos: CGPoint

    var body: some View {
        StrokeTextLabel(text: text)
//            .frame(width: UIScreen.main.bounds.width - 16, height: 40, alignment: .center)
            .position(pos)
            .gesture(dragGesture)
    }

    var dragGesture : some Gesture {
        DragGesture()
            .onChanged { value in
                self.pos = value.location
                print(self.pos)
        }
    }
}

struct StrokeTextLabel: UIViewRepresentable {
    var text: String

    func makeUIView(context: Context) -> UITextField {
        let attributedStringParagraphStyle = NSMutableParagraphStyle()
        attributedStringParagraphStyle.alignment = NSTextAlignment.center
        let attributedString = NSAttributedString(
            string: text,
            attributes:[
                NSAttributedString.Key.strokeColor : UIColor.white,
                NSAttributedString.Key.foregroundColor : UIColor.black,
                NSAttributedString.Key.strokeWidth : -4.0,
                NSAttributedString.Key.font: UIFont(name: "impact", size: 50.0)!
            ]
        )

        let strokeLabel = UITextField(frame: CGRect.zero)
        strokeLabel.attributedText = attributedString
        strokeLabel.backgroundColor = UIColor.clear
        strokeLabel.sizeToFit()
        strokeLabel.center = CGPoint.init(x: 0.0, y: 0.0)
        strokeLabel.sizeToFit()
        return strokeLabel
    }

    func updateUIView(_ uiView: UITextField, context: Context) {}
}

#if DEBUG
struct CustomTextField_Previews: PreviewProvider {
    static var previews: some View {
        CustomTextField(text: "test text", pos: CGPoint(x: 300, y: 500))
    }
}
#endif

我希望应用程序在单击 return 按钮时关闭键盘,但应用程序会冻结。

此答案的来源归功于 https://github.com/valvoline/SATextField/blob/master/SATextField/ContentView.swift。如果没有上述来源,这个答案就不会在这里。

没有什么大的变化。

struct CustomTextField: View {
    @State var text: String
    @State var pos: CGPoint

    var body: some View {
        StrokeTextLabel(text: $text, changeHandler: { newString in
            self.text = newString
        }, onCommitHandler: {
            print("commitHandler")
        })
            .position(pos)
            .gesture(dragGesture)
    }

    var dragGesture : some Gesture {
        DragGesture()
            .onChanged { value in
                self.pos = value.location
                print(self.pos)
        }
    }
}

添加了 UITextField 和 UITextFieldDelegate 以使用它们的功能

class WrappableTextField: UITextField, UITextFieldDelegate {
    var textFieldChangedHandler: ((String)->Void)?
    var onCommitHandler: (()->Void)?

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if let currentValue = textField.text as NSString? {
            let proposedValue = currentValue.replacingCharacters(in: range, with: string)
            textFieldChangedHandler?(proposedValue as String)
        }
        return true
    }

    func textFieldDidEndEditing(_ textField: UITextField) {
        onCommitHandler?()
    }
}

将委托用作对象并添加属性。还使字符串成为 Binding

struct StrokeTextLabel: UIViewRepresentable {
    private let tmpView = WrappableTextField()

    @Binding var text: String

    //var exposed to SwiftUI object init
    var changeHandler:((String)->Void)?
    var onCommitHandler:(()->Void)?

    func makeUIView(context: Context) -> UITextField {
        tmpView.delegate = tmpView
        tmpView.onCommitHandler = onCommitHandler
        tmpView.textFieldChangedHandler = changeHandler


        let attributedStringParagraphStyle = NSMutableParagraphStyle()
        attributedStringParagraphStyle.alignment = NSTextAlignment.center
        let attributedString = NSAttributedString(
            string: text,
            attributes:[
                NSAttributedString.Key.strokeColor : UIColor.white,
                NSAttributedString.Key.foregroundColor : UIColor.black,
                NSAttributedString.Key.strokeWidth : -4.0,
                NSAttributedString.Key.font: UIFont(name: "impact", size: 50.0)!
            ]
        )

        tmpView.attributedText = attributedString
        tmpView.autocorrectionType = .no
        tmpView.keyboardType = .default

        return tmpView
    }

    func updateUIView(_ uiView: UITextField, context: Context) {
        uiView.setContentHuggingPriority(.defaultHigh, for: .vertical)
        uiView.setContentHuggingPriority(.defaultLow, for: .horizontal)
    }
}