Pobieranie i ustawianie pozycji kursora UITextField i UITextView w języku Swift

109

Eksperymentowałem UITextFieldi jak pracować z jego pozycją kursora. Znalazłem wiele odpowiedzi w relacji Cel-C, jak w

Ale ponieważ pracuję z Swiftem, chciałem dowiedzieć się, jak uzyskać bieżącą lokalizację kursora, a także ustawić ją w Swift.

Odpowiedź poniżej jest wynikiem moich eksperymentów i tłumaczenia z Objective-C.

Suragch
źródło

Odpowiedzi:

316

Poniższa treść dotyczy obu UITextFieldi UITextView.

Przydatna informacja

Sam początek tekstu pola tekstowego:

let startPosition: UITextPosition = textField.beginningOfDocument

Sam koniec tekstu pola tekstowego:

let endPosition: UITextPosition = textField.endOfDocument

Aktualnie wybrany zakres:

let selectedRange: UITextRange? = textField.selectedTextRange

Uzyskaj pozycję kursora

if let selectedRange = textField.selectedTextRange {

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

    print("\(cursorPosition)")
}

Ustaw pozycję kursora

Aby ustawić pozycję, wszystkie te metody w rzeczywistości ustawiają zakres z tymi samymi wartościami początkowymi i końcowymi.

Do początku

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

Do końca

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

Do jednej pozycji na lewo od aktualnej pozycji kursora

// 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)
    }
}

Na dowolne stanowisko

Zacznij od początku i przesuń 5 znaków w prawo.

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

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

Związane z

Zaznacz cały tekst

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

Wybierz zakres tekstu

// 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!)
}

Wstaw tekst w bieżącej pozycji kursora

textField.insertText("Hello")

Uwagi

  • Służy textField.becomeFirstResponder()do zaznaczania pola tekstowego i wyświetlania klawiatury.

  • Zobacz tę odpowiedź, aby dowiedzieć się, jak uzyskać tekst w pewnym zakresie.

Zobacz też

Suragch
źródło
Jaki jest cel startPosition? Co możesz z tym zrobić? Jaki jest cel, jaki może być potrzebny, aby uzyskać pozycję kursora?
Miód
2
@ Kochanie, użyłem tej nazwy zmiennej, aby odnieść się tutaj do dwóch różnych rzeczy. Pierwsza dotyczyła początku pola tekstowego. Byłoby to przydatne, gdybyś chciał przenieść tam kursor. Drugi miał odnosić się do początku wybranego zakresu tekstu. Jest to przydatne, jeśli chcesz skopiować ten zakres lub ustawić na nim jakiś atrybut.
Suragch
Czy jest coś do przesunięcia kursora w prawo, gdy pole tekstowe jest puste? Poszedłem za twoją odpowiedzią, ale nie mogłem.
Yucel Bayram
1
@yucelbayram, możesz umieścić kursor po H za pomocą textField.endOfDocument. Możesz również użyć podkreślenia lub spacji, aby przedstawić brakujące litery.
Suragch
1
@ArielSD, przepraszam, nie pracowałem nad tym przez jakiś czas. Nie pamiętam.
Suragch,
42

w moim przypadku musiałem użyć DispatchQueue:

func textViewDidBeginEditing(_ textView: UITextView) {

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

nic innego z tego i innych wątków nie działało.

PS: Dokładnie sprawdziłem, w którym wątku działa textViewDidBeginEditing i był to główny wątek, ponieważ cały interfejs użytkownika powinien działać, więc nie jestem pewien, dlaczego zadziałało to niewielkie opóźnienie przy użyciu main.asynch.

Michael Ros
źródło
2
To nie jest opóźnienie, ale następna pętla uruchamiania. Najprawdopodobniej wybrany zakres pola tekstowego jest modyfikowany przez tę samą funkcję, która wywołała textViewDidBeginEditing. Więc umieszczając go w kolejce, nastąpi to po zakończeniu dzwoniącego.
Michael Ozeryansky,
@MichaelOzeryansky Tak, też tak myślę. Ale to nasuwa pytanie - jaka jest właściwa metoda ręcznego ustawiania pozycji kursora?
harmonogramowonder
to rozwiązanie sprawdziło się również w moim przypadku
Hattori Hanzō
1

Aby ustawić położenie kursora w miejscu:

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

Resetowanie pozycji kursora:

textView.endFloatingCursor()

Uwaga : ten przykład działa zarówno w widoku tekstowym, jak i w polu tekstowym.

Parth Patel
źródło
@Suragch Floating Cursor to jedna z metod ustawiania położenia kursora w textView lub textField.
Parth Patel
1
let range = field.selectedTextRange

field.text = "hello world"

field.selectedTextRange = range 
Ivan
źródło