Obtener y configurar la posición del cursor de UITextField y UITextView en Swift

109

He estado experimentando UITextFieldy cómo trabajar con la posición del cursor. Encontré una serie de respuestas Objective-C de relación, como en

Pero como estoy trabajando con Swift, quería aprender cómo obtener la ubicación actual del cursor y también configurarlo en Swift.

La respuesta a continuación es el resultado de mi experimentación y traducción de Objective-C.

Suragch
fuente

Respuestas:

316

El siguiente contenido se aplica a ambos UITextFieldy UITextView.

Información útil

El comienzo del texto del campo de texto:

let startPosition: UITextPosition = textField.beginningOfDocument

El final del texto del campo de texto:

let endPosition: UITextPosition = textField.endOfDocument

El rango seleccionado actualmente:

let selectedRange: UITextRange? = textField.selectedTextRange

Obtener la posición del cursor

if let selectedRange = textField.selectedTextRange {

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

    print("\(cursorPosition)")
}

Establecer la posición del cursor

Para establecer la posición, todos estos métodos en realidad establecen un rango con los mismos valores iniciales y finales.

Al Principio

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

Hasta el final

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

A una posición a la izquierda de la posición actual del cursor

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

A una posición arbitraria

Empiece por el principio y mueva 5 caracteres hacia la derecha.

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

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

Relacionado

Seleccionar todo el texto

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

Seleccionar un rango de texto

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

Insertar texto en la posición actual del cursor

textField.insertText("Hello")

Notas

  • Úselo textField.becomeFirstResponder()para enfocar el campo de texto y hacer que aparezca el teclado.

  • Vea esta respuesta para saber cómo obtener el texto en algún rango.

Ver también

Suragch
fuente
¿Cuál es el propósito de startPosition? ¿Qué puedes hacer con eso? Además, ¿cuál es el propósito que uno podría necesitar para obtener la posición del cursor?
Miel
2
@Honey, usé ese nombre de variable para referirme a dos cosas diferentes aquí. El primero fue hacer referencia al comienzo del campo de texto. Sería útil si quisiera mover el cursor allí. El segundo era referirse al principio de un rango de texto seleccionado. Es útil si desea copiar ese rango o establecer algún atributo en él.
Suragch
¿Hay algo para mover el cursor hacia la derecha mientras el campo de texto está vacío? Seguí tu respuesta pero no pude hacerlo.
Yucel Bayram
1
@yucelbayram, puede colocar el cursor después de la H usando textField.endOfDocument. También puede usar guiones bajos o espacios para representar las letras que faltan.
Suragch
1
@ArielSD, lo siento, no he trabajado en esto por un tiempo. No puedo recordar.
Suragch
42

en mi caso tuve que usar DispatchQueue:

func textViewDidBeginEditing(_ textView: UITextView) {

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

nada más de este y otros hilos funcionó.

PD: Verifiqué dos veces en qué hilo se estaba ejecutando textViewDidBeginEditing, y era el hilo principal, ya que toda la interfaz de usuario debería ejecutarse, así que no estoy seguro de por qué funcionó ese pequeño retraso con main.asynch.

Michael Ros
fuente
2
No es un retraso, sino el siguiente ciclo de ejecución. Lo más probable es que el rango seleccionado del campo de texto esté siendo modificado por la misma función que llamó textViewDidBeginEditing. Entonces, al colocarlo en la cola, sucederá después de que la persona que llama haya terminado.
Michael Ozeryansky
@MichaelOzeryansky Sí, yo también lo creo. Pero esto plantea la pregunta: ¿cuál ES el método correcto para establecer la posición del cursor manualmente?
timetowonder
También funcionó esta solución en mi caso
Hattori Hanzō
1

Para establecer la posición del cursor en su punto:

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

Para restablecer la posición del cursor:

textView.endFloatingCursor()

Nota : Este ejemplo funciona tanto en Textview como en Textfield.

Parth Patel
fuente
@Suragch Floating Cursor es un método para establecer la ubicación del cursor en textView o textField.
Parth Patel
1
let range = field.selectedTextRange

field.text = "hello world"

field.selectedTextRange = range 
Iván
fuente