Prevent user from setting cursor position on UITextField
Asked Answered
C

7

17

I have an UITextField constructed using the storyboard. I want to not allow the user to change the position of the cursor and keep it always at the end of the text into the text field.

I tried to change the position of the cursor at the touchdown event, but when selecting the text field and then change the position of the cursor by touching the text field again, the position is changed:

- (IBAction)amountBoxTouchDown:(id)sender {
    UITextPosition *start = [amountBox positionFromPosition:[amountBox beginningOfDocument] offset:amountBox.text.length];
    UITextPosition *end = [amountBox positionFromPosition:start
                                                   offset:0];
    [amountBox setSelectedTextRange:[amountBox textRangeFromPosition:start toPosition:end]];
}

Does anyone know a solution? Thanks

Cyclostome answered 7/5, 2013 at 12:29 Comment(1)
Please explain why you want to disable cursor position. Maybe there is another solution.Thief
P
1

Ok, what you have to do is have a UITextField that is hidden.

Add that hidden text field to the view, and call becomeFirstResponder on it. From your amountBoxTouchDown: method.

In the Textfield delegate, take the text the user typed in and add it to amountBox.text. Also turn off userInteractionEnabled for the visible amountBox textField.

This creates the effect you desire.

Have a look at for some sample code Link.

Parris answered 7/5, 2013 at 12:38 Comment(4)
I have tried this, but the keyboard will dismiss after disabling the user interaction!!Cyclostome
I have written the code under the view controller file. I have set textField.userInteractionEnabled = NO just in the touchDown function, I can't have the keyboard displayed. The code is mentioned in my question above, I have just deleted the call of the textField.userInteractionEnabled = NO.Cyclostome
This is a good solution but it is not adapted to my custom use. Thanks any way.Cyclostome
I don't like this because it looks like a hack and is unclear to the readerLorola
P
32

Simply create a subclass of UITextField and override the closestPositionToPoint method:

- (UITextPosition *)closestPositionToPoint:(CGPoint)point{
    UITextPosition *beginning = self.beginningOfDocument;
    UITextPosition *end = [self positionFromPosition:beginning offset:self.text.length];
    return end;
}

Now the user will be unable to move cursor, it will be always in the end of field.

SWIFT:

override func closestPosition(to point: CGPoint) -> UITextPosition? {
    let beginning = self.beginningOfDocument
    let end = self.position(from: beginning, offset: self.text?.count ?? 0)
    return end
}
Prussiate answered 28/5, 2014 at 19:2 Comment(5)
Nice solution. override func closestPosition(to point: CGPoint) -> UITextPosition? { let begining = self.beginningOfDocument let end = self.position(from: begining, offset: (self.text?.characters.count)!) return end }Stoneblind
Works great. Thank youPeeler
It worked, now how to move the cursor to selected position using the same override method.Estriol
@Estriol find appropriate question in Stackoverflow or create a new one if none found,Prussiate
This should be the accepted answer. Nice and clean solutionMelodics
C
7

Disable any gesture recognizers on the text field after it has become first responder. This allows it to receive the initial tap, but prevents the user from interacting with the field while it is the first responder. This keeps the system behavior of keeping the cursor at the end of the text without allowing the user to override it.

In a UITextField subclass, add the following:

SWIFT 3.1:

override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    return !isFirstResponder
}

In your storyboard, change the class of your text field to your UITextField subclass.

Calciferol answered 15/6, 2017 at 20:52 Comment(0)
M
5

If you are interested in always keeping your cursor at the end of the text, do this:

override func closestPosition(to point: CGPoint) -> UITextPosition? {
    return self.endOfDocument
}
Multifarious answered 21/1, 2018 at 19:56 Comment(2)
This should have been the accepted answer, cause why take the beginningOfDocument and add offset (like in the most upvoted answer) if you could simply set endOfDocument? :) Not to mention that disabling interaction completely will prevent you from other actions (like selecting/pasting etc). Kudos to you, @kotyara!Kaffir
This also breaks text selection and the cursor can still be moved with the cursor keys of a hardware keyboard.Freesia
T
2

Think in layers and of controls as tools that you can combine to achieve functionality.

If you simply place a UIButton over top a UITextField and change the button type to Custom, you can prevent all touch events on the text field such as moving the cursor, selecting text, copying, cutting, and pasting.

By default, a custom button is transparent.

Create an action so that when the button is touched, the text field becomes the first responder.

Thief answered 7/5, 2013 at 13:9 Comment(4)
I tried with UIButton and UIView on top of UITextField. i disable both userInteactionEnable = NO and made it clear color, but it's not working. UITextField by view hierarchy will be next who gets touch events, so it will allow you to position view. I use @purrrminator solution.Gaudet
I don't suggest you add more UI when you can just modify the behaviour of the textfield you're using.Lorola
But how do you block the two finger ipad keyboard swipe, this will also move the cursor without touching the uitextfieldBuggs
And also 3D Touch on the iPhone keyboard has the same effect as two fingers on the iPad keyboardPerjury
P
1

Ok, what you have to do is have a UITextField that is hidden.

Add that hidden text field to the view, and call becomeFirstResponder on it. From your amountBoxTouchDown: method.

In the Textfield delegate, take the text the user typed in and add it to amountBox.text. Also turn off userInteractionEnabled for the visible amountBox textField.

This creates the effect you desire.

Have a look at for some sample code Link.

Parris answered 7/5, 2013 at 12:38 Comment(4)
I have tried this, but the keyboard will dismiss after disabling the user interaction!!Cyclostome
I have written the code under the view controller file. I have set textField.userInteractionEnabled = NO just in the touchDown function, I can't have the keyboard displayed. The code is mentioned in my question above, I have just deleted the call of the textField.userInteractionEnabled = NO.Cyclostome
This is a good solution but it is not adapted to my custom use. Thanks any way.Cyclostome
I don't like this because it looks like a hack and is unclear to the readerLorola
S
1

Extension of @kas-kad's solution. I created a subclass of UITextView, with this

var enableCursorMotion = true

override func closestPosition(to point: CGPoint) -> UITextPosition? {
    if enableCursorMotion {
        return super.closestPosition(to: point)
    }
    else {
        let beginning = self.beginningOfDocument
        let end = self.position(from: beginning, offset: (self.text?.count)!)
        return end
    }
}
Sunken answered 1/12, 2017 at 17:53 Comment(0)
S
1

Why not use the textFieldDidChangeSelection method from UITextFieldDelegate?

With the below implementation the cursor is always in the end.

And you don't have to create a subclass of your UITextField

func textFieldDidChangeSelection(_ textField: UITextField) {
        let position = textField.endOfDocument
        textField.selectedTextRange = textField.textRange(from: position, to: position)
}

A drawback of this is that you can't mark the text or even see the menu with select, paste etc options.

Semiotics answered 11/1, 2022 at 23:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.