IQKeyboardReturnKeyHandler.m 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  1. //
  2. // IQKeyboardReturnKeyHandler.m
  3. // https://github.com/hackiftekhar/IQKeyboardManager
  4. // Copyright (c) 2013-16 Iftekhar Qurashi.
  5. //
  6. // Permission is hereby granted, free of charge, to any person obtaining a copy
  7. // of this software and associated documentation files (the "Software"), to deal
  8. // in the Software without restriction, including without limitation the rights
  9. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. // copies of the Software, and to permit persons to whom the Software is
  11. // furnished to do so, subject to the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included in
  14. // all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. // THE SOFTWARE.
  23. #import "IQKeyboardReturnKeyHandler.h"
  24. #import "IQKeyboardManager.h"
  25. #import "IQUIView+Hierarchy.h"
  26. #import "IQNSArray+Sort.h"
  27. #import <UIKit/UITextField.h>
  28. #import <UIKit/UITextView.h>
  29. #import <UIKit/UIViewController.h>
  30. @interface IQTextFieldViewInfoModal : NSObject
  31. @property(nullable, nonatomic, weak) UIView *textFieldView;
  32. @property(nullable, nonatomic, weak) id<UITextFieldDelegate> textFieldDelegate;
  33. @property(nullable, nonatomic, weak) id<UITextViewDelegate> textViewDelegate;
  34. @property(nonatomic) UIReturnKeyType originalReturnKeyType;
  35. @end
  36. @implementation IQTextFieldViewInfoModal
  37. -(instancetype)initWithTextFieldView:(UIView*)textFieldView textFieldDelegate:(id<UITextFieldDelegate>)textFieldDelegate textViewDelegate:(id<UITextViewDelegate>)textViewDelegate originalReturnKey:(UIReturnKeyType)returnKeyType
  38. {
  39. self = [super init];
  40. if (self)
  41. {
  42. _textFieldView = textFieldView;
  43. _textFieldDelegate = textFieldDelegate;
  44. _textViewDelegate = textViewDelegate;
  45. _originalReturnKeyType = returnKeyType;
  46. }
  47. return self;
  48. }
  49. @end
  50. @interface IQKeyboardReturnKeyHandler ()<UITextFieldDelegate,UITextViewDelegate>
  51. -(void)updateReturnKeyTypeOnTextField:(UIView*)textField;
  52. @end
  53. @implementation IQKeyboardReturnKeyHandler
  54. {
  55. NSMutableSet<IQTextFieldViewInfoModal*> *textFieldInfoCache;
  56. }
  57. @synthesize lastTextFieldReturnKeyType = _lastTextFieldReturnKeyType;
  58. @synthesize delegate = _delegate;
  59. - (instancetype)init
  60. {
  61. self = [self initWithViewController:nil];
  62. return self;
  63. }
  64. -(instancetype)initWithViewController:(nullable UIViewController*)controller
  65. {
  66. self = [super init];
  67. if (self)
  68. {
  69. textFieldInfoCache = [[NSMutableSet alloc] init];
  70. if (controller.view)
  71. {
  72. [self addResponderFromView:controller.view];
  73. }
  74. }
  75. return self;
  76. }
  77. -(IQTextFieldViewInfoModal*)textFieldViewCachedInfo:(UIView*)textField
  78. {
  79. for (IQTextFieldViewInfoModal *modal in textFieldInfoCache)
  80. if (modal.textFieldView == textField) return modal;
  81. return nil;
  82. }
  83. #pragma mark - Add/Remove TextFields
  84. -(void)addResponderFromView:(UIView*)view
  85. {
  86. NSArray<UIView*> *textFields = [view deepResponderViews];
  87. for (UIView *textField in textFields) [self addTextFieldView:textField];
  88. }
  89. -(void)removeResponderFromView:(UIView*)view
  90. {
  91. NSArray<UIView*> *textFields = [view deepResponderViews];
  92. for (UIView *textField in textFields) [self removeTextFieldView:textField];
  93. }
  94. -(void)removeTextFieldView:(UIView*)view
  95. {
  96. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:view];
  97. if (modal)
  98. {
  99. UITextField *textField = (UITextField*)view;
  100. if ([view respondsToSelector:@selector(setReturnKeyType:)])
  101. {
  102. textField.returnKeyType = modal.originalReturnKeyType;
  103. }
  104. if ([view respondsToSelector:@selector(setDelegate:)])
  105. {
  106. textField.delegate = modal.textFieldDelegate;
  107. }
  108. [textFieldInfoCache removeObject:modal];
  109. }
  110. }
  111. -(void)addTextFieldView:(UIView*)view
  112. {
  113. IQTextFieldViewInfoModal *modal = [[IQTextFieldViewInfoModal alloc] initWithTextFieldView:view textFieldDelegate:nil textViewDelegate:nil originalReturnKey:UIReturnKeyDefault];
  114. UITextField *textField = (UITextField*)view;
  115. if ([view respondsToSelector:@selector(setReturnKeyType:)])
  116. {
  117. modal.originalReturnKeyType = textField.returnKeyType;
  118. }
  119. if ([view respondsToSelector:@selector(setDelegate:)])
  120. {
  121. modal.textFieldDelegate = textField.delegate;
  122. [textField setDelegate:self];
  123. }
  124. [textFieldInfoCache addObject:modal];
  125. }
  126. -(void)updateReturnKeyTypeOnTextField:(UIView*)textField
  127. {
  128. UIView *superConsideredView;
  129. //If find any consider responderView in it's upper hierarchy then will get deepResponderView. (Bug ID: #347)
  130. for (Class consideredClass in [[IQKeyboardManager sharedManager] toolbarPreviousNextAllowedClasses])
  131. {
  132. superConsideredView = [textField superviewOfClassType:consideredClass];
  133. if (superConsideredView)
  134. break;
  135. }
  136. NSArray<UIView*> *textFields = nil;
  137. //If there is a tableView in view's hierarchy, then fetching all it's subview that responds. No sorting for tableView, it's by subView position.
  138. if (superConsideredView) // // (Enhancement ID: #22)
  139. {
  140. textFields = [superConsideredView deepResponderViews];
  141. }
  142. //Otherwise fetching all the siblings
  143. else
  144. {
  145. textFields = [textField responderSiblings];
  146. //Sorting textFields according to behaviour
  147. switch ([[IQKeyboardManager sharedManager] toolbarManageBehaviour])
  148. {
  149. //If needs to sort it by tag
  150. case IQAutoToolbarByTag:
  151. textFields = [textFields sortedArrayByTag];
  152. break;
  153. //If needs to sort it by Position
  154. case IQAutoToolbarByPosition:
  155. textFields = [textFields sortedArrayByPosition];
  156. break;
  157. default:
  158. break;
  159. }
  160. }
  161. //If it's the last textField in responder view, else next
  162. [(UITextField*)textField setReturnKeyType:(([textFields lastObject] == textField) ? self.lastTextFieldReturnKeyType : UIReturnKeyNext)];
  163. }
  164. #pragma mark - Goto next or Resign.
  165. -(BOOL)goToNextResponderOrResign:(UIView*)textField
  166. {
  167. UIView *superConsideredView;
  168. //If find any consider responderView in it's upper hierarchy then will get deepResponderView. (Bug ID: #347)
  169. for (Class consideredClass in [[IQKeyboardManager sharedManager] toolbarPreviousNextAllowedClasses])
  170. {
  171. superConsideredView = [textField superviewOfClassType:consideredClass];
  172. if (superConsideredView)
  173. break;
  174. }
  175. NSArray<UIView*> *textFields = nil;
  176. //If there is a tableView in view's hierarchy, then fetching all it's subview that responds. No sorting for tableView, it's by subView position.
  177. if (superConsideredView) // // (Enhancement ID: #22)
  178. {
  179. textFields = [superConsideredView deepResponderViews];
  180. }
  181. //Otherwise fetching all the siblings
  182. else
  183. {
  184. textFields = [textField responderSiblings];
  185. //Sorting textFields according to behaviour
  186. switch ([[IQKeyboardManager sharedManager] toolbarManageBehaviour])
  187. {
  188. //If needs to sort it by tag
  189. case IQAutoToolbarByTag:
  190. textFields = [textFields sortedArrayByTag];
  191. break;
  192. //If needs to sort it by Position
  193. case IQAutoToolbarByPosition:
  194. textFields = [textFields sortedArrayByPosition];
  195. break;
  196. default:
  197. break;
  198. }
  199. }
  200. //Getting index of current textField.
  201. NSUInteger index = [textFields indexOfObject:textField];
  202. //If it is not last textField. then it's next object becomeFirstResponder.
  203. if (index != NSNotFound && index < textFields.count-1)
  204. {
  205. [textFields[index+1] becomeFirstResponder];
  206. return NO;
  207. }
  208. else
  209. {
  210. [textField resignFirstResponder];
  211. return YES;
  212. }
  213. }
  214. #pragma mark - TextField delegate
  215. - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
  216. {
  217. id<UITextFieldDelegate> delegate = self.delegate;
  218. if (delegate == nil)
  219. {
  220. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
  221. delegate = modal.textFieldDelegate;
  222. }
  223. if ([delegate respondsToSelector:@selector(textFieldShouldBeginEditing:)])
  224. return [delegate textFieldShouldBeginEditing:textField];
  225. else
  226. return YES;
  227. }
  228. - (void)textFieldDidBeginEditing:(UITextField *)textField
  229. {
  230. [self updateReturnKeyTypeOnTextField:textField];
  231. id<UITextFieldDelegate> delegate = self.delegate;
  232. if (delegate == nil)
  233. {
  234. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
  235. delegate = modal.textFieldDelegate;
  236. }
  237. if ([delegate respondsToSelector:@selector(textFieldDidBeginEditing:)])
  238. [delegate textFieldDidBeginEditing:textField];
  239. }
  240. - (BOOL)textFieldShouldEndEditing:(UITextField *)textField
  241. {
  242. id<UITextFieldDelegate> delegate = self.delegate;
  243. if (delegate == nil)
  244. {
  245. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
  246. delegate = modal.textFieldDelegate;
  247. }
  248. if ([delegate respondsToSelector:@selector(textFieldShouldEndEditing:)])
  249. return [delegate textFieldShouldEndEditing:textField];
  250. else
  251. return YES;
  252. }
  253. - (void)textFieldDidEndEditing:(UITextField *)textField
  254. {
  255. id<UITextFieldDelegate> delegate = self.delegate;
  256. if (delegate == nil)
  257. {
  258. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
  259. delegate = modal.textFieldDelegate;
  260. }
  261. if ([delegate respondsToSelector:@selector(textFieldDidEndEditing:)])
  262. [delegate textFieldDidEndEditing:textField];
  263. }
  264. - (void)textFieldDidEndEditing:(UITextField *)textField reason:(UITextFieldDidEndEditingReason)reason NS_AVAILABLE_IOS(10_0);
  265. {
  266. id<UITextFieldDelegate> delegate = self.delegate;
  267. if (delegate == nil)
  268. {
  269. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
  270. delegate = modal.textFieldDelegate;
  271. }
  272. if (@available(iOS 10.0, *)) {
  273. if ([delegate respondsToSelector:@selector(textFieldDidEndEditing:reason:)])
  274. [delegate textFieldDidEndEditing:textField reason:reason];
  275. }
  276. }
  277. - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
  278. {
  279. id<UITextFieldDelegate> delegate = self.delegate;
  280. if (delegate == nil)
  281. {
  282. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
  283. delegate = modal.textFieldDelegate;
  284. }
  285. if ([delegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)])
  286. return [delegate textField:textField shouldChangeCharactersInRange:range replacementString:string];
  287. else
  288. return YES;
  289. }
  290. #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 160000
  291. - (UIMenu *)textField:(UITextField *)textField editMenuForCharactersInRange:(NSRange)range suggestedActions:(NSArray<UIMenuElement *> *)suggestedActions NS_AVAILABLE_IOS(16_0);
  292. {
  293. id<UITextFieldDelegate> delegate = self.delegate;
  294. if (delegate == nil)
  295. {
  296. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
  297. delegate = modal.textFieldDelegate;
  298. }
  299. if ([delegate respondsToSelector:@selector(textField:editMenuForCharactersInRange:suggestedActions:)])
  300. return [delegate textField:textField editMenuForCharactersInRange:range suggestedActions:suggestedActions];
  301. else
  302. return nil;
  303. }
  304. - (void)textField:(UITextField *)textField willPresentEditMenuWithAnimator:(id<UIEditMenuInteractionAnimating>)animator NS_AVAILABLE_IOS(16_0);
  305. {
  306. id<UITextFieldDelegate> delegate = self.delegate;
  307. if (delegate == nil)
  308. {
  309. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
  310. delegate = modal.textFieldDelegate;
  311. }
  312. if ([delegate respondsToSelector:@selector(textField:willPresentEditMenuWithAnimator:)])
  313. [delegate textField:textField willPresentEditMenuWithAnimator:animator];
  314. }
  315. - (void)textField:(UITextField *)textField willDismissEditMenuWithAnimator:(id<UIEditMenuInteractionAnimating>)animator NS_AVAILABLE_IOS(16_0);
  316. {
  317. id<UITextFieldDelegate> delegate = self.delegate;
  318. if (delegate == nil)
  319. {
  320. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
  321. delegate = modal.textFieldDelegate;
  322. }
  323. if ([delegate respondsToSelector:@selector(textField:willDismissEditMenuWithAnimator:)])
  324. [delegate textField:textField willDismissEditMenuWithAnimator:animator];
  325. }
  326. #endif
  327. - (BOOL)textFieldShouldClear:(UITextField *)textField
  328. {
  329. id<UITextFieldDelegate> delegate = self.delegate;
  330. if (delegate == nil)
  331. {
  332. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
  333. delegate = modal.textFieldDelegate;
  334. }
  335. if ([delegate respondsToSelector:@selector(textFieldShouldClear:)])
  336. return [delegate textFieldShouldClear:textField];
  337. else
  338. return YES;
  339. }
  340. -(BOOL)textFieldShouldReturn:(UITextField *)textField
  341. {
  342. id<UITextFieldDelegate> delegate = self.delegate;
  343. if (delegate == nil)
  344. {
  345. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
  346. delegate = modal.textFieldDelegate;
  347. }
  348. if ([delegate respondsToSelector:@selector(textFieldShouldReturn:)])
  349. {
  350. BOOL shouldReturn = [delegate textFieldShouldReturn:textField];
  351. if (shouldReturn)
  352. {
  353. shouldReturn = [self goToNextResponderOrResign:textField];
  354. }
  355. return shouldReturn;
  356. }
  357. else
  358. {
  359. return [self goToNextResponderOrResign:textField];
  360. }
  361. }
  362. #pragma mark - TextView delegate
  363. - (BOOL)textViewShouldBeginEditing:(UITextView *)textView
  364. {
  365. id<UITextViewDelegate> delegate = self.delegate;
  366. if (delegate == nil)
  367. {
  368. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  369. delegate = modal.textViewDelegate;
  370. }
  371. if ([delegate respondsToSelector:@selector(textViewShouldBeginEditing:)])
  372. return [delegate textViewShouldBeginEditing:textView];
  373. else
  374. return YES;
  375. }
  376. - (BOOL)textViewShouldEndEditing:(UITextView *)textView
  377. {
  378. id<UITextViewDelegate> delegate = self.delegate;
  379. if (delegate == nil)
  380. {
  381. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  382. delegate = modal.textViewDelegate;
  383. }
  384. if ([delegate respondsToSelector:@selector(textViewShouldEndEditing:)])
  385. return [delegate textViewShouldEndEditing:textView];
  386. else
  387. return YES;
  388. }
  389. - (void)textViewDidBeginEditing:(UITextView *)textView
  390. {
  391. [self updateReturnKeyTypeOnTextField:textView];
  392. id<UITextViewDelegate> delegate = self.delegate;
  393. if (delegate == nil)
  394. {
  395. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  396. delegate = modal.textViewDelegate;
  397. }
  398. if ([delegate respondsToSelector:@selector(textViewDidBeginEditing:)])
  399. [delegate textViewDidBeginEditing:textView];
  400. }
  401. - (void)textViewDidEndEditing:(UITextView *)textView
  402. {
  403. id<UITextViewDelegate> delegate = self.delegate;
  404. if (delegate == nil)
  405. {
  406. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  407. delegate = modal.textViewDelegate;
  408. }
  409. if ([delegate respondsToSelector:@selector(textViewDidEndEditing:)])
  410. [delegate textViewDidEndEditing:textView];
  411. }
  412. - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
  413. {
  414. id<UITextViewDelegate> delegate = self.delegate;
  415. if (delegate == nil)
  416. {
  417. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  418. delegate = modal.textViewDelegate;
  419. }
  420. BOOL shouldReturn = YES;
  421. if ([delegate respondsToSelector:@selector(textView:shouldChangeTextInRange:replacementText:)])
  422. shouldReturn = [delegate textView:textView shouldChangeTextInRange:range replacementText:text];
  423. if (shouldReturn && [text isEqualToString:@"\n"])
  424. {
  425. shouldReturn = [self goToNextResponderOrResign:textView];
  426. }
  427. return shouldReturn;
  428. }
  429. - (void)textViewDidChange:(UITextView *)textView
  430. {
  431. id<UITextViewDelegate> delegate = self.delegate;
  432. if (delegate == nil)
  433. {
  434. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  435. delegate = modal.textViewDelegate;
  436. }
  437. if ([delegate respondsToSelector:@selector(textViewDidChange:)])
  438. [delegate textViewDidChange:textView];
  439. }
  440. - (void)textViewDidChangeSelection:(UITextView *)textView
  441. {
  442. id<UITextViewDelegate> delegate = self.delegate;
  443. if (delegate == nil)
  444. {
  445. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  446. delegate = modal.textViewDelegate;
  447. }
  448. if ([delegate respondsToSelector:@selector(textViewDidChangeSelection:)])
  449. [delegate textViewDidChangeSelection:textView];
  450. }
  451. - (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction NS_AVAILABLE_IOS(10_0);
  452. {
  453. id<UITextViewDelegate> delegate = self.delegate;
  454. if (delegate == nil)
  455. {
  456. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  457. delegate = modal.textViewDelegate;
  458. }
  459. if (@available(iOS 10.0, *)) {
  460. if ([delegate respondsToSelector:@selector(textView:shouldInteractWithURL:inRange:interaction:)])
  461. return [delegate textView:textView shouldInteractWithURL:URL inRange:characterRange interaction:interaction];
  462. }
  463. return YES;
  464. }
  465. - (BOOL)textView:(UITextView *)textView shouldInteractWithTextAttachment:(NSTextAttachment *)textAttachment inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction NS_AVAILABLE_IOS(10_0);
  466. {
  467. id<UITextViewDelegate> delegate = self.delegate;
  468. if (delegate == nil)
  469. {
  470. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  471. delegate = modal.textViewDelegate;
  472. }
  473. if (@available(iOS 10.0, *)) {
  474. if ([delegate respondsToSelector:@selector(textView:shouldInteractWithTextAttachment:inRange:interaction:)])
  475. return [delegate textView:textView shouldInteractWithTextAttachment:textAttachment inRange:characterRange interaction:interaction];
  476. }
  477. return YES;
  478. }
  479. #if __IPHONE_OS_VERSION_MIN_REQUIRED < 100000
  480. - (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
  481. {
  482. id<UITextViewDelegate> delegate = self.delegate;
  483. if (delegate == nil)
  484. {
  485. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  486. delegate = modal.textViewDelegate;
  487. }
  488. if ([delegate respondsToSelector:@selector(textView:shouldInteractWithURL:inRange:)])
  489. return [delegate textView:textView shouldInteractWithURL:URL inRange:characterRange];
  490. else
  491. return YES;
  492. }
  493. - (BOOL)textView:(UITextView *)textView shouldInteractWithTextAttachment:(NSTextAttachment *)textAttachment inRange:(NSRange)characterRange
  494. {
  495. id<UITextViewDelegate> delegate = self.delegate;
  496. if (delegate == nil)
  497. {
  498. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  499. delegate = modal.textViewDelegate;
  500. }
  501. if ([delegate respondsToSelector:@selector(textView:shouldInteractWithTextAttachment:inRange:)])
  502. return [delegate textView:textView shouldInteractWithTextAttachment:textAttachment inRange:characterRange];
  503. else
  504. return YES;
  505. }
  506. #endif
  507. #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 160000
  508. -(UIMenu *)textView:(UITextView *)textView editMenuForTextInRange:(NSRange)range suggestedActions:(NSArray<UIMenuElement *> *)suggestedActions NS_AVAILABLE_IOS(16_0);
  509. {
  510. id<UITextViewDelegate> delegate = self.delegate;
  511. if (delegate == nil)
  512. {
  513. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  514. delegate = modal.textViewDelegate;
  515. }
  516. if ([delegate respondsToSelector:@selector(textView:editMenuForTextInRange:suggestedActions:)])
  517. return [delegate textView:textView editMenuForTextInRange:range suggestedActions:suggestedActions];
  518. else
  519. return nil;
  520. }
  521. - (void)textView:(UITextView *)textView willPresentEditMenuWithAnimator:(id<UIEditMenuInteractionAnimating>)animator NS_AVAILABLE_IOS(16_0);
  522. {
  523. id<UITextViewDelegate> delegate = self.delegate;
  524. if (delegate == nil)
  525. {
  526. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  527. delegate = modal.textViewDelegate;
  528. }
  529. if ([delegate respondsToSelector:@selector(textView:willPresentEditMenuWithAnimator:)])
  530. [delegate textView:textView willPresentEditMenuWithAnimator:animator];
  531. }
  532. - (void)textView:(UITextView *)textView willDismissEditMenuWithAnimator:(id<UIEditMenuInteractionAnimating>)animator NS_AVAILABLE_IOS(16_0);
  533. {
  534. id<UITextViewDelegate> delegate = self.delegate;
  535. if (delegate == nil)
  536. {
  537. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  538. delegate = modal.textViewDelegate;
  539. }
  540. if ([delegate respondsToSelector:@selector(textView:willDismissEditMenuWithAnimator:)])
  541. [delegate textView:textView willDismissEditMenuWithAnimator:animator];
  542. }
  543. #endif
  544. -(void)dealloc
  545. {
  546. for (IQTextFieldViewInfoModal *modal in textFieldInfoCache)
  547. {
  548. UITextField *textField = (UITextField*)modal.textFieldView;
  549. if ([textField respondsToSelector:@selector(setReturnKeyType:)])
  550. {
  551. textField.returnKeyType = modal.originalReturnKeyType;
  552. }
  553. if ([textField respondsToSelector:@selector(setDelegate:)])
  554. {
  555. textField.delegate = modal.textFieldDelegate;
  556. }
  557. }
  558. [textFieldInfoCache removeAllObjects];
  559. }
  560. @end