简体   繁体   中英

Hide the cursor of a UITextField

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?

Simply subclass UITextField and override caretRectForPosition

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

从 iOS 7 开始,您现在只需在 textField 上设置tintColor = [UIColor clearColor] ,插入符号就会消失。

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;

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

set the tintColor to Clear Color

textfield.tintColor = [UIColor clearColor];

and you can also set from the interface builder

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

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 like cleaner = less code, use the interface builder:

清晰的颜色

(Attributes inspector, view section.)

In my case, overriding the caret rect wasn't enough. On iOS 15, the caret didn't appear, effectively, but the selection handles did.

Solved it with: override var canBecomeFirstResponder: Bool { return false } on the UITextView subclass.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM