web-dev-qa-db-ja.com

値を設定した後にUITextFieldでカーソルを移動する方法

誰かがこれで私を助けることができます:入力番号にUITextFieldを実装する必要があります。この数値は常に4桁の10進数形式である必要があります。 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メソッド呼び出しの後、これは自動的に変更され、Origin UITextRangeが失われます(現在の)。うまくいけば、私の説明は明確です。

これで私を助けてください。どうもありがとうございました。

[〜#〜] edit [〜#〜]:最後に、全体の編集後に機能をフォーマットの変更に切り替えることにし、十分に機能します。セレクタforControlEvents:UIControlEventEditingDidEndを追加することでそれを実現しました。

27
user1135839

後に UITextField.textプロパティが変更され、古いテキストに関連付けられていたUITextPositionまたはUITextRangeオブジェクトへの以前の参照は、テキストプロパティを設定した後でnilに設定されます。テキストプロパティを設定する前に、操作後のテキストオフセットを保存する必要があります。

これは私にとってはうまくいきました(注、以下の例でtから文字を削除する場合、cursorOffsetが<textField.text.lengthであるかどうかをテストする必要があります):

- (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;
}
41
JasonD

Swift 3バージョン

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

そして、Swift versionです:

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
}
3
ergunkocak

この回答で説明されているコードを実装します。 ITextFieldの先頭にカーソルを移動

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

EDIT:this answer から、iOS 5を使用している場合、UITextFieldでこのコードを使用できるようです以上。それ以外の場合は、代わりにUITextViewを使用する必要があります。

2
gtmtg

実際に機能したのは非常にシンプルで、dispatch main asyncを使用しただけです。

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

SwiftX。カーソルを最後の位置から移動しないようにします。

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)
    }
}
0
Mike Glukhov