IQKeyboardReturnKeyHandler.m 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  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. if ([view isKindOfClass:[UITextField class]])
  100. {
  101. UITextField *textField = (UITextField*)view;
  102. textField.returnKeyType = modal.originalReturnKeyType;
  103. textField.delegate = modal.textFieldDelegate;
  104. }
  105. else if ([view isKindOfClass:[UITextView class]])
  106. {
  107. UITextView *textView = (UITextView*)view;
  108. textView.returnKeyType = modal.originalReturnKeyType;
  109. textView.delegate = modal.textViewDelegate;
  110. }
  111. [textFieldInfoCache removeObject:modal];
  112. }
  113. }
  114. -(void)addTextFieldView:(UIView*)view
  115. {
  116. IQTextFieldViewInfoModal *modal = [[IQTextFieldViewInfoModal alloc] initWithTextFieldView:view textFieldDelegate:nil textViewDelegate:nil originalReturnKey:UIReturnKeyDefault];
  117. if ([view isKindOfClass:[UITextField class]])
  118. {
  119. UITextField *textField = (UITextField*)view;
  120. modal.originalReturnKeyType = textField.returnKeyType;
  121. modal.textFieldDelegate = textField.delegate;
  122. [textField setDelegate:self];
  123. }
  124. else if ([view isKindOfClass:[UITextView class]])
  125. {
  126. UITextView *textView = (UITextView*)view;
  127. modal.originalReturnKeyType = textView.returnKeyType;
  128. modal.textViewDelegate = textView.delegate;
  129. [textView setDelegate:self];
  130. }
  131. [textFieldInfoCache addObject:modal];
  132. }
  133. -(void)updateReturnKeyTypeOnTextField:(UIView*)textField
  134. {
  135. UIView *superConsideredView;
  136. //If find any consider responderView in it's upper hierarchy then will get deepResponderView. (Bug ID: #347)
  137. for (Class consideredClass in [[IQKeyboardManager sharedManager] toolbarPreviousNextAllowedClasses])
  138. {
  139. superConsideredView = [textField superviewOfClassType:consideredClass];
  140. if (superConsideredView)
  141. break;
  142. }
  143. NSArray<UIView*> *textFields = nil;
  144. //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.
  145. if (superConsideredView) // // (Enhancement ID: #22)
  146. {
  147. textFields = [superConsideredView deepResponderViews];
  148. }
  149. //Otherwise fetching all the siblings
  150. else
  151. {
  152. textFields = [textField responderSiblings];
  153. //Sorting textFields according to behaviour
  154. switch ([[IQKeyboardManager sharedManager] toolbarManageBehaviour])
  155. {
  156. //If needs to sort it by tag
  157. case IQAutoToolbarByTag:
  158. textFields = [textFields sortedArrayByTag];
  159. break;
  160. //If needs to sort it by Position
  161. case IQAutoToolbarByPosition:
  162. textFields = [textFields sortedArrayByPosition];
  163. break;
  164. default:
  165. break;
  166. }
  167. }
  168. //If it's the last textField in responder view, else next
  169. [(UITextField*)textField setReturnKeyType:(([textFields lastObject] == textField) ? self.lastTextFieldReturnKeyType : UIReturnKeyNext)];
  170. }
  171. #pragma mark - Goto next or Resign.
  172. -(BOOL)goToNextResponderOrResign:(UIView*)textField
  173. {
  174. UIView *superConsideredView;
  175. //If find any consider responderView in it's upper hierarchy then will get deepResponderView. (Bug ID: #347)
  176. for (Class consideredClass in [[IQKeyboardManager sharedManager] toolbarPreviousNextAllowedClasses])
  177. {
  178. superConsideredView = [textField superviewOfClassType:consideredClass];
  179. if (superConsideredView)
  180. break;
  181. }
  182. NSArray<UIView*> *textFields = nil;
  183. //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.
  184. if (superConsideredView) // // (Enhancement ID: #22)
  185. {
  186. textFields = [superConsideredView deepResponderViews];
  187. }
  188. //Otherwise fetching all the siblings
  189. else
  190. {
  191. textFields = [textField responderSiblings];
  192. //Sorting textFields according to behaviour
  193. switch ([[IQKeyboardManager sharedManager] toolbarManageBehaviour])
  194. {
  195. //If needs to sort it by tag
  196. case IQAutoToolbarByTag:
  197. textFields = [textFields sortedArrayByTag];
  198. break;
  199. //If needs to sort it by Position
  200. case IQAutoToolbarByPosition:
  201. textFields = [textFields sortedArrayByPosition];
  202. break;
  203. default:
  204. break;
  205. }
  206. }
  207. //Getting index of current textField.
  208. NSUInteger index = [textFields indexOfObject:textField];
  209. //If it is not last textField. then it's next object becomeFirstResponder.
  210. if (index != NSNotFound && index < textFields.count-1)
  211. {
  212. [textFields[index+1] becomeFirstResponder];
  213. return NO;
  214. }
  215. else
  216. {
  217. [textField resignFirstResponder];
  218. return YES;
  219. }
  220. }
  221. #pragma mark - TextField delegate
  222. - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
  223. {
  224. id<UITextFieldDelegate> delegate = self.delegate;
  225. if (delegate == nil)
  226. {
  227. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
  228. delegate = modal.textFieldDelegate;
  229. }
  230. if ([delegate respondsToSelector:@selector(textFieldShouldBeginEditing:)])
  231. return [delegate textFieldShouldBeginEditing:textField];
  232. else
  233. return YES;
  234. }
  235. - (void)textFieldDidBeginEditing:(UITextField *)textField
  236. {
  237. [self updateReturnKeyTypeOnTextField:textField];
  238. id<UITextFieldDelegate> delegate = self.delegate;
  239. if (delegate == nil)
  240. {
  241. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
  242. delegate = modal.textFieldDelegate;
  243. }
  244. if ([delegate respondsToSelector:@selector(textFieldDidBeginEditing:)])
  245. [delegate textFieldDidBeginEditing:textField];
  246. }
  247. - (BOOL)textFieldShouldEndEditing:(UITextField *)textField
  248. {
  249. id<UITextFieldDelegate> delegate = self.delegate;
  250. if (delegate == nil)
  251. {
  252. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
  253. delegate = modal.textFieldDelegate;
  254. }
  255. if ([delegate respondsToSelector:@selector(textFieldShouldEndEditing:)])
  256. return [delegate textFieldShouldEndEditing:textField];
  257. else
  258. return YES;
  259. }
  260. - (void)textFieldDidEndEditing:(UITextField *)textField
  261. {
  262. id<UITextFieldDelegate> delegate = self.delegate;
  263. if (delegate == nil)
  264. {
  265. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
  266. delegate = modal.textFieldDelegate;
  267. }
  268. if ([delegate respondsToSelector:@selector(textFieldDidEndEditing:)])
  269. [delegate textFieldDidEndEditing:textField];
  270. }
  271. - (void)textFieldDidEndEditing:(UITextField *)textField reason:(UITextFieldDidEndEditingReason)reason NS_AVAILABLE_IOS(10_0);
  272. {
  273. id<UITextFieldDelegate> delegate = self.delegate;
  274. if (delegate == nil)
  275. {
  276. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
  277. delegate = modal.textFieldDelegate;
  278. }
  279. #ifdef __IPHONE_11_0
  280. if (@available(iOS 10.0, *)) {
  281. #endif
  282. if ([delegate respondsToSelector:@selector(textFieldDidEndEditing:reason:)])
  283. [delegate textFieldDidEndEditing:textField reason:reason];
  284. #ifdef __IPHONE_11_0
  285. }
  286. #endif
  287. }
  288. - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
  289. {
  290. id<UITextFieldDelegate> delegate = self.delegate;
  291. if (delegate == nil)
  292. {
  293. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
  294. delegate = modal.textFieldDelegate;
  295. }
  296. if ([delegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)])
  297. return [delegate textField:textField shouldChangeCharactersInRange:range replacementString:string];
  298. else
  299. return YES;
  300. }
  301. - (BOOL)textFieldShouldClear:(UITextField *)textField
  302. {
  303. id<UITextFieldDelegate> delegate = self.delegate;
  304. if (delegate == nil)
  305. {
  306. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
  307. delegate = modal.textFieldDelegate;
  308. }
  309. if ([delegate respondsToSelector:@selector(textFieldShouldClear:)])
  310. return [delegate textFieldShouldClear:textField];
  311. else
  312. return YES;
  313. }
  314. -(BOOL)textFieldShouldReturn:(UITextField *)textField
  315. {
  316. id<UITextFieldDelegate> delegate = self.delegate;
  317. if (delegate == nil)
  318. {
  319. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
  320. delegate = modal.textFieldDelegate;
  321. }
  322. if ([delegate respondsToSelector:@selector(textFieldShouldReturn:)])
  323. {
  324. BOOL shouldReturn = [delegate textFieldShouldReturn:textField];
  325. if (shouldReturn)
  326. {
  327. shouldReturn = [self goToNextResponderOrResign:textField];
  328. }
  329. return shouldReturn;
  330. }
  331. else
  332. {
  333. return [self goToNextResponderOrResign:textField];
  334. }
  335. }
  336. #pragma mark - TextView delegate
  337. - (BOOL)textViewShouldBeginEditing:(UITextView *)textView
  338. {
  339. id<UITextViewDelegate> delegate = self.delegate;
  340. if (delegate == nil)
  341. {
  342. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  343. delegate = modal.textViewDelegate;
  344. }
  345. if ([delegate respondsToSelector:@selector(textViewShouldBeginEditing:)])
  346. return [delegate textViewShouldBeginEditing:textView];
  347. else
  348. return YES;
  349. }
  350. - (BOOL)textViewShouldEndEditing:(UITextView *)textView
  351. {
  352. id<UITextViewDelegate> delegate = self.delegate;
  353. if (delegate == nil)
  354. {
  355. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  356. delegate = modal.textViewDelegate;
  357. }
  358. if ([delegate respondsToSelector:@selector(textViewShouldEndEditing:)])
  359. return [delegate textViewShouldEndEditing:textView];
  360. else
  361. return YES;
  362. }
  363. - (void)textViewDidBeginEditing:(UITextView *)textView
  364. {
  365. [self updateReturnKeyTypeOnTextField:textView];
  366. id<UITextViewDelegate> delegate = self.delegate;
  367. if (delegate == nil)
  368. {
  369. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  370. delegate = modal.textViewDelegate;
  371. }
  372. if ([delegate respondsToSelector:@selector(textViewDidBeginEditing:)])
  373. [delegate textViewDidBeginEditing:textView];
  374. }
  375. - (void)textViewDidEndEditing:(UITextView *)textView
  376. {
  377. id<UITextViewDelegate> delegate = self.delegate;
  378. if (delegate == nil)
  379. {
  380. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  381. delegate = modal.textViewDelegate;
  382. }
  383. if ([delegate respondsToSelector:@selector(textViewDidEndEditing:)])
  384. [delegate textViewDidEndEditing:textView];
  385. }
  386. - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
  387. {
  388. id<UITextViewDelegate> delegate = self.delegate;
  389. if (delegate == nil)
  390. {
  391. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  392. delegate = modal.textViewDelegate;
  393. }
  394. BOOL shouldReturn = YES;
  395. if ([delegate respondsToSelector:@selector(textView:shouldChangeTextInRange:replacementText:)])
  396. shouldReturn = [delegate textView:textView shouldChangeTextInRange:range replacementText:text];
  397. if (shouldReturn && [text isEqualToString:@"\n"])
  398. {
  399. shouldReturn = [self goToNextResponderOrResign:textView];
  400. }
  401. return shouldReturn;
  402. }
  403. - (void)textViewDidChange:(UITextView *)textView
  404. {
  405. id<UITextViewDelegate> delegate = self.delegate;
  406. if (delegate == nil)
  407. {
  408. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  409. delegate = modal.textViewDelegate;
  410. }
  411. if ([delegate respondsToSelector:@selector(textViewDidChange:)])
  412. [delegate textViewDidChange:textView];
  413. }
  414. - (void)textViewDidChangeSelection:(UITextView *)textView
  415. {
  416. id<UITextViewDelegate> delegate = self.delegate;
  417. if (delegate == nil)
  418. {
  419. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  420. delegate = modal.textViewDelegate;
  421. }
  422. if ([delegate respondsToSelector:@selector(textViewDidChangeSelection:)])
  423. [delegate textViewDidChangeSelection:textView];
  424. }
  425. - (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction NS_AVAILABLE_IOS(10_0);
  426. {
  427. id<UITextViewDelegate> delegate = self.delegate;
  428. if (delegate == nil)
  429. {
  430. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  431. delegate = modal.textViewDelegate;
  432. }
  433. #ifdef __IPHONE_11_0
  434. if (@available(iOS 10.0, *)) {
  435. #endif
  436. if ([delegate respondsToSelector:@selector(textView:shouldInteractWithURL:inRange:interaction:)])
  437. return [delegate textView:textView shouldInteractWithURL:URL inRange:characterRange interaction:interaction];
  438. #ifdef __IPHONE_11_0
  439. }
  440. #endif
  441. return YES;
  442. }
  443. - (BOOL)textView:(UITextView *)textView shouldInteractWithTextAttachment:(NSTextAttachment *)textAttachment inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction NS_AVAILABLE_IOS(10_0);
  444. {
  445. id<UITextViewDelegate> delegate = self.delegate;
  446. if (delegate == nil)
  447. {
  448. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  449. delegate = modal.textViewDelegate;
  450. }
  451. #ifdef __IPHONE_11_0
  452. if (@available(iOS 10.0, *)) {
  453. #endif
  454. if ([delegate respondsToSelector:@selector(textView:shouldInteractWithTextAttachment:inRange:interaction:)])
  455. return [delegate textView:textView shouldInteractWithTextAttachment:textAttachment inRange:characterRange interaction:interaction];
  456. #ifdef __IPHONE_11_0
  457. }
  458. #endif
  459. return YES;
  460. }
  461. - (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
  462. {
  463. id<UITextViewDelegate> delegate = self.delegate;
  464. if (delegate == nil)
  465. {
  466. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  467. delegate = modal.textViewDelegate;
  468. }
  469. #pragma clang diagnostic push
  470. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  471. if ([delegate respondsToSelector:@selector(textView:shouldInteractWithURL:inRange:)])
  472. return [delegate textView:textView shouldInteractWithURL:URL inRange:characterRange];
  473. #pragma clang diagnostic pop
  474. else
  475. return YES;
  476. }
  477. - (BOOL)textView:(UITextView *)textView shouldInteractWithTextAttachment:(NSTextAttachment *)textAttachment inRange:(NSRange)characterRange
  478. {
  479. id<UITextViewDelegate> delegate = self.delegate;
  480. if (delegate == nil)
  481. {
  482. IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
  483. delegate = modal.textViewDelegate;
  484. }
  485. #pragma clang diagnostic push
  486. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  487. if ([delegate respondsToSelector:@selector(textView:shouldInteractWithTextAttachment:inRange:)])
  488. return [delegate textView:textView shouldInteractWithTextAttachment:textAttachment inRange:characterRange];
  489. #pragma clang diagnostic pop
  490. else
  491. return YES;
  492. }
  493. -(void)dealloc
  494. {
  495. for (IQTextFieldViewInfoModal *modal in textFieldInfoCache)
  496. {
  497. UIView *textFieldView = modal.textFieldView;
  498. if ([textFieldView isKindOfClass:[UITextField class]])
  499. {
  500. UITextField *textField = (UITextField*)textFieldView;
  501. textField.returnKeyType = modal.originalReturnKeyType;
  502. textField.delegate = modal.textFieldDelegate
  503. ;
  504. }
  505. else if ([textFieldView isKindOfClass:[UITextView class]])
  506. {
  507. UITextView *textView = (UITextView*)textFieldView;
  508. textView.returnKeyType = modal.originalReturnKeyType;
  509. textView.delegate = modal.textViewDelegate;
  510. }
  511. }
  512. [textFieldInfoCache removeAllObjects];
  513. }
  514. @end