SwiftUI: как отключить «умные кавычки» в TextEditor

Я разрабатываю графический калькулятор на основе Python для MacOS с использованием SwiftUI.

https://github.com/snakajima/macplot

Я использую SwiftUI TextEditor в качестве редактора кода Python, но я не могу понять, как отключить умную цитату (UITextInputTraits, smartQuotesType: UITextSmartQuotesType).

              VStack {
            TextEditor(text: $pythonScript.script)
            HStack {
                Button(action: {
                    pythonScript.run(clear: settings.shouldClear)
                }, label: {
                    Text("Plot")
                })
                Toggle("Clear", isOn: $settings.shouldClear)
            }
            if let errorMsg = pythonScript.errorMsg {
                Text(errorMsg)
                    .foregroundColor(.pink)
            }
        }

5 ответов

После нескольких попыток я нашел следующий обходной путь. Он основан на том факте, что TextEditor реализован поверх NSTextView и меняет его поведение во всем приложении. Это некрасиво, но работает.

      // HACK to work-around the smart quote issue
extension NSTextView {
    open override var frame: CGRect {
        didSet {
            self.isAutomaticQuoteSubstitutionEnabled = false
        }
    }
}

Для тех, кто ищет ответ для UIKit (iOS, iPadOS) вместо AppKit (macOS), это работает для меня, используя аналогичный подход. Спасибо Сатоши!

      extension UITextView {
    open override var frame: CGRect {
        didSet {
            self.smartQuotesType = UITextSmartQuotesType.no
        }
    }
}

Это имеет те же недостатки, а именно то, что все текстовые поля в вашем приложении потеряют автоматические умные кавычки, но, по крайней мере, вы можете контролировать это, если вам это нужно.

Я использовал SwiftUI Introspect , чтобы отключить это для моегоTextEditor.

                  TextEditor(text: $text)
                .introspect(.textEditor, on: .macOS(.v14, .v13)) { nsTextView in
                    nsTextView.isAutomaticQuoteSubstitutionEnabled = false
                    nsTextView.isAutomaticDashSubstitutionEnabled = false
                }

Другим решением было бы написатьNSTextViewобертка:

      struct TextView: NSViewRepresentable {
    @Binding var text: String
    private var customizations = [(NSTextView) -> Void]()

    init(text: Binding<String>) {
        _text = text
    }

    func makeNSView(context: Context) -> NSView {
        NSTextView()
    }

    func updateNSView(_ nsView: NSView, context: Context) {
        let textView = nsView as! NSTextView
        textView.string = text
        customizations.forEach { $0(textView) }
    }

    func automaticDashSubstitutionEnabled(_ enabled: Bool) -> Self {
        customized { $0.isAutomaticDashSubstitutionEnabled = enabled }
    }

    func automaticQuoteSubstitutionEnabled(_ enabled: Bool) -> Self {
        customized { $0.isAutomaticQuoteSubstitutionEnabled = enabled }
    }

    func automaticSpellingCorrectionEnabled(_ enabled: Bool) -> Self {
        customized { $0.isAutomaticSpellingCorrectionEnabled = enabled }
    }
}

private extension TextView {
    func customized(_ customization: @escaping (NSTextView) -> Void) -> Self {
        var copy = self
        copy.customizations.append(customization)
        return copy
    }
}

, который можно использовать следующим образом:

      TextView(text: $myText)
    .automaticDashSubstitutionEnabled(false)
    .automaticQuoteSubstitutionEnabled(false)
    .automaticSpellingCorrectionEnabled(false)

Я тоже боролся с этим и поэтому в конце концов исправил смарт-кавычки, заменив их прямыми кавычками при вводе текстового поля. Я знаю, что это хак, но он работает.

      TextEditor(text: $Mytext)
.onChange(of: Mytext) { 
                        newValue in
                        Mytext = Mytext.replacingOccurrences(of: "“", with: "\"") // replaces smart quotes
                        Mytext = Mytext.replacingOccurrences(of: "”", with: "\"")
                        Mytext = Mytext.replacingOccurrences(of: "‘", with: "'")
                        Mytext = Mytext.replacingOccurrences(of: "’", with: "'")
}
Другие вопросы по тегам