Obtendo e definindo a posição do cursor de UITextField e UITextView em Swift

109

Tenho experimentado UITextFielde como trabalhar com a posição do cursor. Eu encontrei uma série de respostas de relação Objective-C, como em

Mas, como estou trabalhando com o Swift, gostaria de aprender como obter a localização atual do cursor e também defini-la no Swift.

A resposta abaixo é o resultado da minha experimentação e tradução do Objective-C.

Suragch
fonte

Respostas:

316

O conteúdo a seguir se aplica a ambos UITextFielde UITextView.

Informação útil

O início do texto do campo de texto:

let startPosition: UITextPosition = textField.beginningOfDocument

O final do texto do campo de texto:

let endPosition: UITextPosition = textField.endOfDocument

O intervalo atualmente selecionado:

let selectedRange: UITextRange? = textField.selectedTextRange

Obter a posição do cursor

if let selectedRange = textField.selectedTextRange {

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

    print("\(cursorPosition)")
}

Definir a posição do cursor

Para definir a posição, todos esses métodos estão, na verdade, definindo um intervalo com os mesmos valores inicial e final.

Para o início

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

Até o fim

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

Para uma posição à esquerda da posição atual do 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)
    }
}

Para uma posição arbitrária

Comece no início e mova 5 caracteres para a direita.

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

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

Relacionados

Selecione todo o texto

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

Selecione um intervalo 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!)
}

Insere texto na posição atual do cursor

textField.insertText("Hello")

Notas

  • Use textField.becomeFirstResponder()para dar foco ao campo de texto e fazer o teclado aparecer.

  • Veja esta resposta para saber como obter o texto em algum intervalo.

Veja também

Suragch
fonte
Qual é o propósito de startPosition? O que você pode fazer com isso? Além disso, qual é o propósito que se pode precisar para obter a posição do cursor?
Honey,
2
@Honey, usei esse nome de variável para se referir a duas coisas diferentes aqui. O primeiro era referir-se ao início do campo de texto. Seria útil se você quisesse mover o cursor até lá. A segunda era referir-se ao início de uma gama selecionada de texto. É útil se você deseja copiar esse intervalo ou definir algum atributo nele.
Suragch
Há algo para mover o cursor para a direita enquanto o campo de texto está vazio? Segui sua resposta, mas não pude comparecer.
Yucel Bayram
1
@yucelbayram, você pode colocar o cursor após o H usando textField.endOfDocument. Você também pode usar sublinhados ou espaços para representar as letras que faltam.
Suragch
1
@ArielSD, sinto muito, não trabalho nisso há um tempo. Eu não consigo lembrar.
Suragch
42

no meu caso, tive que usar DispatchQueue:

func textViewDidBeginEditing(_ textView: UITextView) {

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

nada mais deste e de outros tópicos funcionou.

PS: Eu verifiquei em qual thread textViewDidBeginEditing estava sendo executado, e era o thread principal, já que toda a IU deve ser executada, então não tenho certeza de por que aquele pequeno atraso usando main.asynch funcionou.

Michael Ros
fonte
2
Não é um atraso, mas o próximo ciclo de execução. Provavelmente, o intervalo selecionado do campo de texto está sendo modificado pela mesma função que chamou textViewDidBeginEditing. Portanto, ao colocá-lo na fila, isso acontecerá depois que o chamador terminar.
Michael Ozeryansky,
@MichaelOzeryansky Sim, também acho. Mas isso levanta a questão - qual é o método certo para definir a posição do cursor manualmente?
horário após
funcionou essa solução no meu caso também
Hattori Hanzō
1

Para definir a posição do cursor no seu ponto:

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

Para redefinir a posição do cursor:

textView.endFloatingCursor()

Nota : Este exemplo funciona em Textview e Textfield.

Parth Patel
fonte
@Suragch Floating Cursor é um método para definir a localização do cursor em textView ou textField.
Parth Patel
1
let range = field.selectedTextRange

field.text = "hello world"

field.selectedTextRange = range 
Ivan
fonte