在Swift中获取和设置UITextField和UITextView的光标位置

Sur*_*gch 93 uitextfield uitextview ios uitextposition swift

我一直在尝试UITextField和如何使用它的光标位置.我已经找到了许多关系Objective-C答案,如

但由于我正在使用Swift,我想学习如何获取当前光标位置并在Swift中设置它.

下面的答案是我从Objective-C进行实验和翻译的结果.

Sur*_*gch 271

以下内容适用于UITextFieldUITextView.

有用的信息

文本字段文本的开头:

let startPosition: UITextPosition = textField.beginningOfDocument
Run Code Online (Sandbox Code Playgroud)

文本字段文本的最后:

let endPosition: UITextPosition = textField.endOfDocument
Run Code Online (Sandbox Code Playgroud)

当前选择的范围:

let selectedRange: UITextRange? = textField.selectedTextRange
Run Code Online (Sandbox Code Playgroud)

获取光标位置

if let selectedRange = textField.selectedTextRange {

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

    print("\(cursorPosition)")
}
Run Code Online (Sandbox Code Playgroud)

设置光标位置

为了设置位置,所有这些方法实际上都是设置具有相同开始值和结束值的范围.

到了开始

let newPosition = textField.beginningOfDocument
textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)
Run Code Online (Sandbox Code Playgroud)

到最后

let newPosition = textField.endOfDocument
textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)
Run Code Online (Sandbox Code Playgroud)

到当前光标位置左侧的一个位置

// 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

到任意位置

从头开始,向右移动5个字符.

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

    textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)
}
Run Code Online (Sandbox Code Playgroud)

有关

选择所有文字

textField.selectedTextRange = textField.textRange(from: textField.beginningOfDocument, to: textField.endOfDocument)
Run Code Online (Sandbox Code Playgroud)

选择一系列文字

// 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!)
}
Run Code Online (Sandbox Code Playgroud)

在当前光标位置插入文本

textField.insertText("Hello")
Run Code Online (Sandbox Code Playgroud)

笔记

  • 用于textField.becomeFirstResponder()将焦点置于文本字段并使键盘显示.

  • 有关如何在某个范围内获取文本,请参阅此答案.

也可以看看

  • @Honey,我用这个变量名称来指代两个不同的东西.第一个是引用文本字段的开头.如果你想将光标移动到那里会很有用.第二个是提到选定范围的文本的乞讨.如果要复制该范围或在其上设置某些属性,这将非常有用. (2认同)

Mic*_*Ros 29

在我的情况下,我不得不使用DispatchQueue:

func textViewDidBeginEditing(_ textView: UITextView) {

   DispatchQueue.main.async{
      textField.selectedTextRange = ...
   }
}
Run Code Online (Sandbox Code Playgroud)

这个和其他线程没有其他工作.

PS:我仔细检查了运行textViewDidBeginEditing的线程,并且它是主线程,因为所有UI都应该运行,所以不确定为什么使用main.asynch的那个小延迟工作.

  • 这不是延迟,而是下一个运行循环。很可能文本字段的选定范围正在被称为“textViewDidBeginEditing”的同一函数修改。所以通过把它放在队列中,它会在调用者完成后发生。 (5认同)
  • @MichaelOzeryansky 是的,我也这么认为。但这引出了一个问题——手动设置光标位置的正确方法是什么? (2认同)

Iva*_*van 5

let range = field.selectedTextRange

field.text = "hello world"

field.selectedTextRange = range 
Run Code Online (Sandbox Code Playgroud)