iOS UITextField禁止選中文字(How to disable the selection of a UITextField?)

語言: CN / TW / HK

主題列表:juejin, github, smartblue, cyanosis, channing-cyan, fancy, hydrogen, condensed-night-purple, greenwillow, v-green, vue-pro, healer-readable, mk-cute, jzman, geek-black, awesome-green, qklhk-chocolate

貢獻主題:https://github.com/xitu/juejin-markdown-themes

theme: fancy highlight:


背景:

最近在做輸入框的需求, 要求:

  • 不能顯示選中文字(圖中標註的2)
  • 不能彈出氣泡(圖中標註的1)。

image.png

分析:

  • 不能彈出氣泡(圖中標註的1)。 這個好做,也是搜尋結果中最多的,canPerformAction根據需要返回NO即可。

  • 不能彈出氣泡(圖中標註的1)。 這個就不常見中文搜尋不到,用英文搜尋How to disable the selection of a UITextField?,得到一個答案。 ```ObjC

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

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

  • (BOOL)canPerformAction:(SEL)action withSender:(id)sender { return NO; } ```

UITextField的子類,重寫一下上面的方法,好傢伙游標都沒了。雖然沒有達到理想效果,感覺接近了。 我繼續找官方對幾個API的註釋,找到一個關鍵的方法,大概就是選中文字的繪製矩形框UITextSelectionRect

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

UITextSelectionRect

找到這個關鍵的類,就看下怎麼初始化一個新的rect,返回自己想要的就可以了。 ```ObjC 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 `` 這個類沒有初始化方法,就得繼承一個子類,實現屬性的get方法就可以了。 從屬性的名稱可以看到,rect`就是我們想要的。

1. 返回CGRectZero

ObjC - (CGRect)rect{ return CGRectZero; } image.png 問題:

  1. 矩形框確實縮小了,但是在左上角了。

  2. 使用刪除鍵的時候,還是全部刪除了。 也就是說,我們改變了繪製的矩形,但是還是完全選中的。

2. 返回CGRectNull

objc - (CGRect)rect{ return CGRectNull; } 確實沒有矩形了,但是使用刪除鍵,還是會全部刪除。

最後我們只需要解決最後一個問題:如何取消選中?

如何取消選中?

如何知道當前是否被選中? ```objC // UITextField的子類.m - (NSArray )selectionRectsForRange:(UITextRange )range { NSArray arr = [super selectionRectsForRange:range]; for (UITextSelectionRect tmpRect in arr) { if (tmpRect.rect.size.width > 0) {

    }
}
return arr;

} `` 經過嘗試發現tmpRect.rect.size.width就可以得到選中的寬度,想要自定義選中寬度的就可以動態改變它。 那麼tmpRect.rect.size.width > 0`就可以知道當前被選中了。

如何取消選中?

看到UITextRange大概就能猜到,可以移動游標來取消選中,那就每次選中的時候,將游標移動到末尾。

ObjC // UITextField的子類.m // CSTextSelectionRect是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; }

總結:

  1. 新建UITextField一個子類,重寫selectionRectsForRange方法。(實現沒有選中的顯示效果)
  2. 新建UITextSelectionRect一個子類,重寫rect方法,返回CGRectNull。(實現沒有選中的顯示效果)
  3. 選中的時候,移動游標在末尾。(實現真正沒有選中)