【问题标题】:how to move cursor in UITextField after setting its value设置值后如何在 UITextField 中移动光标
【发布时间】:2012-06-24 20:19:02
【问题描述】:

谁能帮我解决这个问题:我需要为输入号码实现UITextField。此数字应始终为十进制格式,有 4 位,例如12.3456 或 12.3400。 所以我创建了NSNumberFormatter,它可以帮助我处理小数位。

我正在设置UITextField 的值

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string 方法。 我处理输入,使用格式化程序,最后调用[textField setText: myFormattedValue];

这工作正常,但此调用还将光标移动到我的字段末尾。这是不想要的。例如。我的字段中有 12.3400,光标位于开头,用户键入数字 1。结果值为 112.3400,但光标在末尾移动。我想在用户期望时以光标结束(就在最近添加的数字 1 之后)。有一些关于在TextView 中设置光标的主题,但这是UITextField。我还尝试捕获该字段的selectedTextRange,它正确保存了光标位置,但在setText 方法调用之后,它会自动更改并且原点UITextRange 丢失(更改为当前)。希望我的解释很清楚。

请帮帮我。非常感谢您。

编辑:最后,我决定在整个编辑后切换功能以更改格式,并且效果很好。我已经通过添加一个选择器forControlEvents:UIControlEventEditingDidEnd 来做到这一点。

【问题讨论】:

  • 当你读到selectedTextRange时,你能不能不把它复制为类中的一个属性,作为UITextFieldDelegate,然后在setText:之后重新设置它?
  • 菲利普,这行不通。使用 setText 设置文本后,设置文本之前收集的 UITextRange 将重置为 null,因此您无法将其重新应用到完成的 UITextField。

标签: ios uitextfield nsnumberformatter selectedtext


【解决方案1】:

实现此答案中描述的代码:Moving the cursor to the beginning of UITextField

NSRange beginningRange = NSMakeRange(0, 0);
NSRange currentRange = [textField selectedRange];
if(!NSEqualRanges(beginningRange, currentRange))
{
    [textField setSelectedRange:beginningRange];
}

编辑:来自this answer,如果您使用的是 iOS 5 或更高版本,您似乎可以将此代码与您的 UITextField 一起使用。否则,您需要改用 UITextView。

【讨论】:

    【解决方案2】:

    更改 UITextField.text 属性后,在您设置 text 属性后,任何先前对与旧文本关联的 UITextPositionUITextRange 对象的引用都将设置为 nil。您需要在设置 text 属性之前存储操作后的文本偏移量。

    这对我有用(注意,如果在下面的示例中从 t 中删除任何字符,则必须测试 cursorOffset 是否为

    - (BOOL) textField:(UITextField *) textField shouldChangeCharactersInRange:(NSRange) range replacementString:(NSString *) string
    
    {
        UITextPosition *beginning = textField.beginningOfDocument;
        UITextPosition *start = [textField positionFromPosition:beginning offset:range.location];
        UITextPosition *end = [textField positionFromPosition:start offset:range.length];
        UITextRange *textRange = [textField textRangeFromPosition:start toPosition:end];
    
        // this will be the new cursor location after insert/paste/typing
        NSInteger cursorOffset = [textField offsetFromPosition:beginning toPosition:start] + string.length; 
    
        // now apply the text changes that were typed or pasted in to the text field
        [textField replaceRange:textRange withText:string];
    
        // now go modify the text in interesting ways doing our post processing of what was typed...
        NSMutableString *t = [textField.text mutableCopy];
        t = [t upperCaseString];
        // ... etc
    
        // now update the text field and reposition the cursor afterwards
        textField.text = t;
        UITextPosition *newCursorPosition = [textField positionFromPosition:textField.beginningOfDocument offset:cursorOffset];
        UITextRange *newSelectedRange = [textField textRangeFromPosition:newCursorPosition toPosition:newCursorPosition];
        [textField setSelectedTextRange:newSelectedRange];
    
        return NO;
    }
    

    【讨论】:

    • 对我来说效果很好。谢谢你,杰森!
    • tnx 非常多,我在下面为懒惰的人添加了 swift 版本:)
    • 我正在使用 xamarin.ios 并且必须将该方法转换为 C#。整个方法的执行时间慢得令人痛苦,这让快速的编写变得不愉快。作为非 xamarin 用户,您是否也遇到了糟糕的性能?
    • 你能帮我解答这个问题吗:stackoverflow.com/q/53440489/2714877
    【解决方案3】:

    这里是快速版本:

    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
        let beginning = textField.beginningOfDocument
        let start = textField.positionFromPosition(beginning, offset:range.location)
        let end = textField.positionFromPosition(start!, offset:range.length)
        let textRange = textField.textRangeFromPosition(start!, toPosition:end!)
        let cursorOffset = textField.offsetFromPosition(beginning, toPosition:start!) + string.characters.count
    
    // just used same text, use whatever you want :)
        textField.text = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)
    
        let newCursorPosition = textField.positionFromPosition(textField.beginningOfDocument, offset:cursorOffset)
        let newSelectedRange = textField.textRangeFromPosition(newCursorPosition!, toPosition:newCursorPosition!)
        textField.selectedTextRange = newSelectedRange
    
        return false
    }
    

    【讨论】:

    • 我正在使用 xamarin.ios 并且必须将该方法转换为 C#。整个方法的执行时间慢得令人痛苦,这使得快速编写变得不愉快。作为非 xamarin 用户,您是否也遇到了糟糕的表现?
    【解决方案4】:

    这是一个 swift 3 版本

    extension UITextField {
        func setCursor(position: Int) {
            let position = self.position(from: beginningOfDocument, offset: position)!
            selectedTextRange = textRange(from: position, to: position)
        }
    }
    

    【讨论】:

      【解决方案5】:

      实际上对我有用的非常简单,只使用了 dispatch main async:

      DispatchQueue.main.async(execute: {
        textField.selectedTextRange = textField.textRange(from: start, to: end)
      })
      

      【讨论】:

      • 这对我有用。我必须在public func textView( _ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String ) -> Bool下添加
      • 很奇怪,但它有效!似乎移动光标应该发生并发生在下一个运行循环周期
      【解决方案6】:

      斯威夫特 X。 防止光标从最后一个位置移动。

      func textFieldDidChangeSelection(_ textField: UITextField) {
          let point = CGPoint(x: bounds.maxX, y: bounds.height / 2)
          if let textPosition = textField.closestPosition(to: point) {
              textField.selectedTextRange = textField.textRange(from: textPosition, to: textPosition)
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-20
        相关资源
        最近更新 更多