Hide the cursor of an UITextField

独自空忆成欢 提交于 2019-11-28 02:47:25
Joseph Chiu

Simply subclass UITextField and override caretRectForPosition

- (CGRect)caretRectForPosition:(UITextPosition *)position
{
    return CGRectZero;
}

As of iOS 7 you can now just set the tintColor = [UIColor clearColor] on the textField and the caret will disappear.

oldman

You can just clear the textfield's tintColor

self.textField.tintColor = [UIColor clearColor];

Swift 3.0

self.textField.tintColor = .clear

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/

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.

  1. 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];
    
  2. 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;
    
Robert Höglund

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.

Swift 3 version of Net's post

  override func caretRect(for position: UITextPosition) -> CGRect {
    return .zero
  }

  override func selectionRects(for range: UITextRange) -> [Any] {
    return []
  }

  override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    return false
  }

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?

If you want to hide cursor, you can easily use this! It worked for me..

[[textField valueForKey:@"textInputTraits"] setValue:[UIColor clearColor] forKey:@"insertionPointColor"]

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;
}

set the tintColor to Clear Color

textfield.tintColor = [UIColor clearColor];

and you can also set from the interface builder

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.

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!