Hide the cursor of a UITextField
IosCocoa TouchUitextfieldUipickerviewIos Problem Overview
I am using a UITextField
with a UIPickerView
for its inputView
, so that when the user taps the text field, a picker is summoned for them to select an option from.
Nearly everything works, but I have one problem: the cursor still flashes in the text field when it is active, which is ugly and inappropriate, since the user is not expected to type into the field and is not presented with a keyboard. I know I could hackily solve this by setting editing
to NO
on the text field and tracking touches on it, or by replacing it with a custom-styled button, and summoning the picker via code. However, I want to use the UITextFieldDelegate
methods for all the event handling on the text field and hacks such as replacing the text field with a button do not permit this approach.
How can I simply hide the cursor on the UITextField
instead?
Ios Solutions
Solution 1 - Ios
Simply subclass UITextField and override caretRectForPosition
- (CGRect)caretRectForPosition:(UITextPosition *)position
{
return CGRectZero;
}
Solution 2 - Ios
As of iOS 7 you can now just set the tintColor = [UIColor clearColor]
on the textField and the caret will disappear.
Solution 3 - Ios
You can just clear the textfield's tintColor
self.textField.tintColor = [UIColor clearColor];
Swift 3.0
self.textField.tintColor = .clear
Solution 4 - Ios
You might also want to stop the user from selecting, copying or pasting any text so that the only text input comes from the picker view.
- (CGRect) caretRectForPosition:(UITextPosition*) position
{
return CGRectZero;
}
- (NSArray *)selectionRectsForRange:(UITextRange *)range
{
return nil;
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if (action == @selector(copy:) || action == @selector(selectAll:) || action == @selector(paste:))
{
returnNO;
}
return [super canPerformAction:action withSender:sender];
}
http://b2cloud.com.au/tutorial/disabling-the-caret-and-text-entry-in-uitextfields/
Solution 5 - Ios
Check out the property selectedTextRange
of the protocol UITextInput
, to which the class UITextField
conforms. Few! That's a lesson in object-oriented programing right there.
Hide Caret
To hide the caret, nil out the text field's selected text range.
textField.selectedTextRange = nil; // hides caret
Unhide Caret
Here are two ways to unhide the caret.
-
Set the text field's selected text range to the end of the document.
UITextPosition *end = textField.endOfDocument; textField.selectedTextRange = [textField textRangeFromPosition:end toPosition:end];
-
To keep the caret in the same spot, first, store the text field's selected text range to an instance variable.
_textFieldSelectedTextRange = textField.selectedTextRange; textField.selectedTextRange = nil; // hides caret
Then, when you want to unhide the caret, simply set the text field's selected text range back to what it was originally:
textField.selectedTextRange = _textFieldSelectedTextRange; _textFieldLastSelectedTextRange = nil;
Solution 6 - Ios
Answer provided by the OP, copied from the question body to help clean up the ever growing tail of unanswered questions.
I found another solution: subclass UIButton
and override these methods
- (UIView *)inputView {
return inputView_;
}
- (void)setInputView:(UIView *)anInputView {
if (inputView_ != anInputView) {
[inputView_ release];
inputView_ = [anInputView retain];
}
}
- (BOOL)canBecomeFirstResponder {
return YES;
}
Now the button, as a UIResponder
, have a similar behavior than UITextField
and an implementation pretty straightforward.
Solution 7 - Ios
Swift 5 version of Net's post
override func caretRect(for position: UITextPosition) -> CGRect {
return .zero
}
override func selectionRects(for range: UITextRange) -> [UITextSelectionRect] {
return []
}
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return false
}
Solution 8 - Ios
set the tintColor to Clear Color
textfield.tintColor = [UIColor clearColor];
and you can also set from the interface builder
Solution 9 - Ios
If you want to hide cursor, you can easily use this! It worked for me..
[[textField valueForKey:@"textInputTraits"] setValue:[UIColor clearColor] forKey:@"insertionPointColor"]
Solution 10 - Ios
Answer provided by the OP, copied from the question body to help clean up the ever growing tail of unanswered questions.
I think I have the correct solution but If it can be improved will be welcome :) Well, I made a subclass of UITextField and overriden the method that returns the CGRect for the bounds
-(CGRect)textRectForBounds:(CGRect)bounds {
return CGRectZero;
}
The problem? The text doesn't show because the rect is zero. But I added an UILabel as a subview of the control and overridden the setText method so, as we enter a text as usual, the text field text is nil and is the label which shows the text
- (void)setText:(NSString *)aText {
[super setText:nil];
if (aText == nil) {
textLabel_.text = nil;
}
if (![aText isEqualToString:@""]) {
textLabel_.text = aText;
}
}
With this the thing works as expected. Have you know any way to improve it?
Solution 11 - Ios
To both disable cursor and menu I use subclass with these 2 methods:
- (CGRect)caretRectForPosition:(UITextPosition *)position {
return CGRectZero;
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
[UIMenuController sharedMenuController].menuVisible = NO;
self.selectedTextRange = nil;
return NO;
}
Solution 12 - Ios
I simply subclass UITextField
, and override layoutSubviews
as follows:
- (void)layoutSubviews
{
[super layoutSubviews];
for (UIView *v in self.subviews)
{
if ([[[v class] description] rangeOfString:@"UITextSelectionView"].location != NSNotFound)
{
v.hidden = YES;
}
}
}
It's a dirty hack, and may fail in the future (at which point the cursor will be visible again - your app won't crash), but it works.
Solution 13 - Ios
Solution 14 - Ios
You can add a BOOL cursorless
property to UITextField
in a category via associated objects.
@interface UITextField (Cursorless)
@property (nonatomic, assign) BOOL cursorless;
@end
Then use method swizzling to swizzle caretRectForPosition:
with a method that toggles between CGRectZero
and its default value using cursorless
.
This leads to a simple interface via a drop-in category. This is demonstrated in the following files.
Simply drop them in and get the benefit of this simple interface
UITextField
category:
https://github.com/rexmas/RexDK/blob/master/RexDK/UI/UITextField%2BRXCursorless.h
https://github.com/rexmas/RexDK/blob/master/RexDK/UI/UITextField%2BRXCursorless.m
Method Swizzling: https://github.com/rexmas/RexDK/blob/master/RexDK/Foundation/NSObject%2BRXRuntimeAdditions.h https://github.com/rexmas/RexDK/blob/master/RexDK/Foundation/NSObject%2BRXRuntimeAdditions.m