Background:

Recently, I have been making requirements for input box. Requirements:

  • Unable to display selected text (labeled 2 in figure)
  • Bubbles cannot pop (marked 1 in figure).

Analysis:

  • Bubbles cannot pop (marked 1 in figure).

This is easy to do, and is the most searched result. CanPerformAction returns NO as needed.

  • Bubbles cannot pop (marked 1 in figure).

How to disable the selection of a UITextField? Get an answer.

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

- (NSArray *)selectionRectsForRange:(UITextRange *)range {
    return nil;
}

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    return NO;
}
Copy the code

I’m going to subclass UITextField, and I’m going to rewrite the above method, because the cursor is gone. It didn’t quite work out, but it felt close. I went through the official comments on a couple of apis, and I found a key method, which was basically to select the text in the draw rectangle UITextSelectionRect,

- (NSArray<UITextSelectionRect *> *)selectionRectsForRange:(UITextRange *)range API_AVAILABLE(ios(6.0));       // Returns an array of UITextSelectionRects
Copy the code

UITextSelectionRect

Find the key class and see how to initialize a new RECT and return what you want.

UIKIT_EXTERN API_AVAILABLE(ios(6.0)) NS_SWIFT_UI_ACTOR
@interface UITextSelectionRect : NSObject

@property (nonatomic.readonly) CGRect rect;
@property (nonatomic.readonly) NSWritingDirection writingDirection;
@property (nonatomic.readonly) BOOL containsStart; // Returns YES if the rect contains the start of the selection.
@property (nonatomic.readonly) BOOL containsEnd; // Returns YES if the rect contains the end of the selection.
@property (nonatomic.readonly) BOOL isVertical; // Returns YES if the rect is for vertically oriented text.

@end
Copy the code

This class has no initializer, so it has to inherit a subclass that implements the property’s GET method. As you can see from the name of the attribute, rect is what we want.

1. ReturnCGRectZero

- (CGRect)rect{
    return CGRectZero;
}
Copy the code

Question:

  1. The rectangle does shrink, but it’s in the top left corner.

  2. When I use the delete key, I still delete everything.

That is, we changed the rectangle we drew, but it’s still completely selected.

2. ReturnCGRectNull

- (CGRect)rect{
    return CGRectNull;
}
Copy the code

There are no rectangles, but if you use the Delete key, it will delete them all.

Finally, we just need to solve one last question: how do I uncheck?

How do I uncheck it?

How do I know if I’m currently selected?

// UITextField subclass.m
- (NSArray<UITextSelectionRect *> *)selectionRectsForRange:(UITextRange *)range {
    NSArray *arr = [super selectionRectsForRange:range];
    for (UITextSelectionRect *tmpRect in arr) {
        if (tmpRect.rect.size.width > 0) {}}return arr;
}
Copy the code

After trying to find tmPrect.rect.sie.width can get the selected width, want to customize the selected width can change it dynamically. Then tmPrect.rect.sie.width > 0 will know that the current is selected.

How do I uncheck it?

As you can probably guess by looking at UITextRange, you can unselect by moving the cursor to the end of each selection.

// UITextField subclass.m
// CSTextSelectionRect is a subclass of UITextSelectionRect
- (NSArray<UITextSelectionRect *> *)selectionRectsForRange:(UITextRange *)range {
    NSArray *arr = [super selectionRectsForRange:range];
    for (UITextSelectionRect *tmpRect in arr) {
        if (tmpRect.rect.size.width > 0) {
            UITextPosition *endPosition = [self endOfDocument];
            UITextRange *textRange =[self textRangeFromPosition:endPosition
                                                     toPosition:endPosition];
            [self setSelectedTextRange:textRange];
            return@[CSTextSelectionRect.new]; }}return arr;
}
Copy the code

Conclusion:

  1. newUITextFieldA subclass, overrideselectionRectsForRangeMethods. (Achieve unselected display)
  2. newUITextSelectionRectA subclass, overriderectMethod, returnCGRectNull. (Achieve unselected display)
  3. When selected, move cursor at end. (Implementation is not really selected)