Abrufen und Festlegen der Cursorposition von UITextField und UITextView in Swift

109

Ich habe experimentiert UITextFieldund wie man mit der Cursorposition arbeitet. Ich habe eine Reihe von Relation Objective-C-Antworten gefunden, wie in

Da ich jedoch mit Swift arbeite, wollte ich lernen, wie man die aktuelle Cursorposition abruft und sie auch in Swift einstellt.

Die folgende Antwort ist das Ergebnis meiner Experimente und Übersetzungen aus Objective-C.

Suragch
quelle

Antworten:

315

Der folgende Inhalt gilt sowohl für UITextFieldals auch UITextView.

Nützliche Informationen

Ganz am Anfang des Textfeldtextes:

let startPosition: UITextPosition = textField.beginningOfDocument

Ganz am Ende des Textfeldtextes:

let endPosition: UITextPosition = textField.endOfDocument

Der aktuell ausgewählte Bereich:

let selectedRange: UITextRange? = textField.selectedTextRange

Cursorposition abrufen

if let selectedRange = textField.selectedTextRange {

    let cursorPosition = textField.offset(from: textField.beginningOfDocument, to: selectedRange.start)

    print("\(cursorPosition)")
}

Cursorposition einstellen

Um die Position festzulegen, legen alle diese Methoden tatsächlich einen Bereich mit denselben Start- und Endwerten fest.

Zu Beginn

let newPosition = textField.beginningOfDocument
textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)

Bis zum Ende

let newPosition = textField.endOfDocument
textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)

An eine Position links von der aktuellen Cursorposition

// only if there is a currently selected range
if let selectedRange = textField.selectedTextRange {

    // and only if the new position is valid
    if let newPosition = textField.position(from: selectedRange.start, offset: -1) {

        // set the new position
        textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)
    }
}

Zu einer beliebigen Position

Beginnen Sie am Anfang und bewegen Sie 5 Zeichen nach rechts.

let arbitraryValue: Int = 5
if let newPosition = textField.position(from: textField.beginningOfDocument, offset: arbitraryValue) {

    textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)
}

verbunden

Wählen Sie den gesamten Text aus

textField.selectedTextRange = textField.textRange(from: textField.beginningOfDocument, to: textField.endOfDocument)

Wählen Sie einen Textbereich aus

// Range: 3 to 7
let startPosition = textField.position(from: textField.beginningOfDocument, offset: 3)
let endPosition = textField.position(from: textField.beginningOfDocument, offset: 7)

if startPosition != nil && endPosition != nil {
    textField.selectedTextRange = textField.textRange(from: startPosition!, to: endPosition!)
}

Fügen Sie Text an der aktuellen Cursorposition ein

textField.insertText("Hello")

Anmerkungen

  • Verwenden Sie textField.becomeFirstResponder()diese Option, um das Textfeld zu fokussieren und die Tastatur anzuzeigen.

  • In dieser Antwort erfahren Sie, wie Sie den Text in einem bestimmten Bereich abrufen können.

Siehe auch

Suragch
quelle
Was ist der Zweck von startPosition? Was kannst du damit machen? Was ist auch der Zweck, den man möglicherweise benötigt, um die Cursorposition zu erhalten?
Honig
2
@Honey, ich habe diesen Variablennamen verwendet, um hier auf zwei verschiedene Dinge zu verweisen. Das erste war, sich auf den Anfang des Textfeldes zu beziehen. Es wäre nützlich, wenn Sie den Cursor dorthin bewegen möchten. Die zweite bestand darin, sich auf das Betteln eines ausgewählten Textbereichs zu beziehen. Dies ist nützlich, wenn Sie diesen Bereich kopieren oder ein Attribut festlegen möchten.
Suragch
Gibt es etwas, um den Cursor nach rechts zu bewegen, während das Textfeld leer ist? Ich bin deiner Antwort gefolgt, aber ich konnte es nicht schaffen.
Yucel Bayram
1
@yucelbayram, Sie können den Cursor nach dem H mit platzieren textField.endOfDocument. Sie können auch Unterstriche oder Leerzeichen verwenden, um die fehlenden Buchstaben darzustellen.
Suragch
1
@ArielSD, tut mir leid, ich habe eine Weile nicht daran gearbeitet. Ich kann mich nicht erinnern.
Suragch
41

In meinem Fall musste ich DispatchQueue verwenden:

func textViewDidBeginEditing(_ textView: UITextView) {

   DispatchQueue.main.async{
      textField.selectedTextRange = ...
   }
}

nichts anderes von diesem und anderen Threads hat funktioniert.

PS: Ich habe zweimal überprüft, auf welchem ​​Thread textViewDidBeginEditing ausgeführt wurde, und es war Hauptthread, da alle Benutzeroberflächen ausgeführt werden sollten. Daher bin ich mir nicht sicher, warum diese kleine Verzögerung mit main.asynch funktioniert hat.

Michael Ros
quelle
2
Es ist keine Verzögerung, sondern die nächste Laufschleife. Höchstwahrscheinlich wird der ausgewählte Bereich des Textfelds durch dieselbe Funktion geändert, die aufgerufen wurde textViewDidBeginEditing. Wenn Sie es also in die Warteschlange stellen, geschieht dies, nachdem der Anrufer fertig ist.
Michael Ozeryansky
@ MichaelOzeryansky Ja, ich denke auch. Dies wirft jedoch die Frage auf: Was ist die richtige Methode, um die Cursorposition manuell einzustellen?
Zeitplan
1

Zum Einstellen der Cursorposition an Ihrem Punkt:

textView.beginFloatingCursor(at: CGPoint(x: 10.0, y: 10.0))

Zum Zurücksetzen der Cursorposition:

textView.endFloatingCursor()

Hinweis : Dieses Beispiel funktioniert sowohl in Textansicht als auch in Textfeld.

Parth Patel
quelle
@Suragch Floating Cursor ist eine Methode zum Festlegen der Cursorposition in textView oder textField.
Parth Patel
1
let range = field.selectedTextRange

field.text = "hello world"

field.selectedTextRange = range 
Ivan
quelle