YOUPAINIMInputView.m 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812
  1. //
  2. // YOUPAINIMInputView.m
  3. // NIMKit
  4. //
  5. // Created by chris.
  6. // Copyright (c) 2015年 NetEase. All rights reserved.
  7. //
  8. #import "YOUPAINIMInputView.h"
  9. #import <AVFoundation/AVFoundation.h>
  10. #import "YOUPAINIMInputMoreContainerView.h"
  11. #import "YOUPAINIMInputEmoticonContainerView.h"
  12. #import "YOUPAINIMInputAudioRecordIndicatorView.h"
  13. #import "UIView+NIM.h"
  14. #import "NIMInputEmoticonDefine.h"
  15. #import "YOUPAINIMInputEmoticonManager.h"
  16. #import "YOUPAINIMInputToolBar.h"
  17. #import "UIImage+NIMKit.h"
  18. #import "NIMGlobalMacro.h"
  19. #import "NIMContactSelectViewController.h"
  20. #import "NIMKit.h"
  21. #import "NIMKitInfoFetchOption.h"
  22. #import "NIMKitKeyboardInfo.h"
  23. #import "YYKit.h"
  24. @interface YOUPAINIMInputView()<NIMInputToolBarDelegate,NIMInputEmoticonProtocol,NIMContactSelectDelegate>
  25. {
  26. UIView *_emoticonView;
  27. }
  28. @property (nonatomic, strong) YOUPAINIMInputAudioRecordIndicatorView *audioRecordIndicator;
  29. @property (nonatomic, assign) NIMAudioRecordPhase recordPhase;
  30. @property (nonatomic, weak) id<NIMSessionConfig> inputConfig;
  31. @property (nonatomic, weak) id<NIMInputDelegate> inputDelegate;
  32. @property (nonatomic, weak) id<NIMInputActionDelegate> actionDelegate;
  33. @property (nonatomic, assign) CGFloat keyBoardFrameTop; //键盘的frame的top值,屏幕高度 - 键盘高度,由于有旋转的可能,这个值只有当 键盘弹出时才有意义。
  34. @end
  35. @implementation YOUPAINIMInputView
  36. @synthesize emoticonContainer = _emoticonContainer;
  37. @synthesize moreContainer = _moreContainer;
  38. - (instancetype)initWithFrame:(CGRect)frame
  39. config:(id<NIMSessionConfig>)config
  40. {
  41. self = [super initWithFrame:frame];
  42. if (self)
  43. {
  44. _recording = NO;
  45. _recordPhase = AudioRecordPhaseEnd;
  46. _atCache = [[YOUPAINIMInputAtCache alloc] init];
  47. _inputConfig = config;
  48. self.backgroundColor = [UIColor whiteColor];
  49. }
  50. return self;
  51. }
  52. - (void)didMoveToWindow
  53. {
  54. [self setup];
  55. }
  56. - (CGSize)sizeThatFits:(CGSize)size
  57. {
  58. //这里不做.语法 get 操作,会提前初始化组件导致卡顿
  59. CGFloat toolBarHeight = _toolBar.nim_height;
  60. CGFloat containerHeight = 0;
  61. switch (self.status)
  62. {
  63. case NIMInputStatusEmoticon:
  64. _toolBar.emoticonBtn.selected = YES;
  65. _toolBar.recordBtn.selected = NO;
  66. containerHeight = _emoticonContainer.nim_height;
  67. break;
  68. case NIMInputStatusMore:
  69. _toolBar.emoticonBtn.selected = NO;
  70. _toolBar.recordBtn.selected = YES;
  71. containerHeight = _voiceViewContainer.nim_height;
  72. break;
  73. default:
  74. {
  75. _toolBar.emoticonBtn.selected = NO;
  76. _toolBar.recordBtn.selected = NO;
  77. UIEdgeInsets safeArea = UIEdgeInsetsZero;
  78. if (@available(iOS 11.0, *))
  79. {
  80. safeArea = self.superview.safeAreaInsets;
  81. }
  82. //键盘是从最底下弹起的,需要减去安全区域底部的高度
  83. CGFloat keyboardDelta = [NIMKitKeyboardInfo instance].keyboardHeight - safeArea.bottom;
  84. //如果键盘还没有安全区域高,容器的初始值为0;否则则为键盘和安全区域的高度差值,这样可以保证 toolBar 始终在键盘上面
  85. containerHeight = keyboardDelta>0 ? keyboardDelta : 0;
  86. }
  87. break;
  88. }
  89. CGFloat height = toolBarHeight + containerHeight;
  90. CGFloat width = self.superview? self.superview.nim_width : self.nim_width;
  91. return CGSizeMake(width, height);
  92. }
  93. - (void)setInputDelegate:(id<NIMInputDelegate>)delegate
  94. {
  95. _inputDelegate = delegate;
  96. }
  97. - (void)setInputActionDelegate:(id<NIMInputActionDelegate>)actionDelegate
  98. {
  99. _actionDelegate = actionDelegate;
  100. }
  101. - (void)reset
  102. {
  103. self.nim_width = self.superview.nim_width;
  104. [self refreshStatus:NIMInputStatusText];
  105. [self sizeToFit];
  106. }
  107. - (void)refreshStatus:(NIMInputStatus)status
  108. {
  109. self.status = status;
  110. [self.toolBar update:status];
  111. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  112. self.voiceViewContainer.hidden = status != NIMInputStatusMore;
  113. self.emoticonContainer.hidden = status != NIMInputStatusEmoticon;
  114. });
  115. }
  116. - (YOUPAINIMInputAudioRecordIndicatorView *)audioRecordIndicator {
  117. if(!_audioRecordIndicator) {
  118. _audioRecordIndicator = [[YOUPAINIMInputAudioRecordIndicatorView alloc] init];
  119. }
  120. return _audioRecordIndicator;
  121. }
  122. - (void)setRecordPhase:(NIMAudioRecordPhase)recordPhase {
  123. NIMAudioRecordPhase prevPhase = _recordPhase;
  124. _recordPhase = recordPhase;
  125. self.audioRecordIndicator.phase = _recordPhase;
  126. if(prevPhase == AudioRecordPhaseEnd) {
  127. if(AudioRecordPhaseStart == _recordPhase) {
  128. if ([_actionDelegate respondsToSelector:@selector(onStartRecording)]) {
  129. [_actionDelegate onStartRecording];
  130. }
  131. }
  132. } else if (prevPhase == AudioRecordPhaseStart || prevPhase == AudioRecordPhaseRecording) {
  133. if (AudioRecordPhaseEnd == _recordPhase) {
  134. if ([_actionDelegate respondsToSelector:@selector(onStopRecording)]) {
  135. [_actionDelegate onStopRecording];
  136. }
  137. }
  138. } else if (prevPhase == AudioRecordPhaseCancelling) {
  139. if(AudioRecordPhaseEnd == _recordPhase) {
  140. if ([_actionDelegate respondsToSelector:@selector(onCancelRecording)]) {
  141. [_actionDelegate onCancelRecording];
  142. }
  143. }
  144. }
  145. }
  146. - (void)setup
  147. {
  148. if (!_toolBar)
  149. {
  150. _toolBar = [[YOUPAINIMInputToolBar alloc] initWithFrame:CGRectMake(0, 0, self.nim_width, 0)];
  151. }
  152. [self addSubview:_toolBar];
  153. //设置placeholder
  154. NSString *placeholder = [NIMKit sharedKit].config.placeholder;
  155. placeholder = @" 请输入消息…";
  156. [_toolBar setPlaceHolder:placeholder];
  157. _toolBar.backgroundColor = [UIColor whiteColor];
  158. //设置input bar 上的按钮
  159. if ([_inputConfig respondsToSelector:@selector(inputBarItemTypes)]) {
  160. NSArray *types = [_inputConfig inputBarItemTypes];
  161. [_toolBar setInputBarItemTypes:types];
  162. }
  163. _toolBar.delegate = self;
  164. [_toolBar.recordBtn addTarget:self action:@selector(onTouchRecordBtn:) forControlEvents:UIControlEventTouchUpInside];
  165. // [_toolBar.cameraBtn addTarget:self action:@selector(onTouchCameraBtn:) forControlEvents:UIControlEventTouchUpInside];
  166. [_toolBar.photoBtn addTarget:self action:@selector(onTouchPhotoBtn:) forControlEvents:UIControlEventTouchUpInside];
  167. [_toolBar.giftBtn addTarget:self action:@selector(onTouchGiftBtn:) forControlEvents:UIControlEventTouchUpInside];
  168. [_toolBar.videoBtn addTarget:self action:@selector(onTouchVideoBtn:) forControlEvents:UIControlEventTouchUpInside];
  169. [_toolBar.sayHiBtn addTarget:self action:@selector(onTouchSayHiBtn:) forControlEvents:UIControlEventTouchUpInside];
  170. [_toolBar.emoticonBtn addTarget:self action:@selector(onTouchEmoticonBtn:) forControlEvents:UIControlEventTouchUpInside];
  171. [_toolBar.moreMediaBtn addTarget:self action:@selector(onTouchMoreBtn:) forControlEvents:UIControlEventTouchUpInside];
  172. [_toolBar.voiceBtn addTarget:self action:@selector(onTouchVoiceBtn:) forControlEvents:UIControlEventTouchUpInside];
  173. _toolBar.nim_size = [_toolBar sizeThatFits:CGSizeMake(self.nim_width, CGFLOAT_MAX)];
  174. _toolBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  175. [_toolBar.recordButton setTitle:@"按住 说话" forState:UIControlStateNormal];
  176. [_toolBar.recordButton setTitle:@"松开 结束" forState:UIControlStateSelected];
  177. [_toolBar.recordButton setHidden:YES];
  178. //设置最大输入字数
  179. NSInteger textInputLength = [NIMKit sharedKit].config.inputMaxLength;
  180. self.maxTextLength = textInputLength;
  181. [self refreshStatus:NIMInputStatusText];
  182. [self sizeToFit];
  183. }
  184. - (void)checkMoreContainer
  185. {
  186. if (!_moreContainer) {
  187. YOUPAINIMInputMoreContainerView *moreContainer = [[YOUPAINIMInputMoreContainerView alloc] initWithFrame:CGRectZero];
  188. moreContainer.nim_size = [moreContainer sizeThatFits:CGSizeMake(self.nim_width, CGFLOAT_MAX)];
  189. moreContainer.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  190. moreContainer.hidden = YES;
  191. moreContainer.config = _inputConfig;
  192. moreContainer.actionDelegate = self.actionDelegate;
  193. _moreContainer = moreContainer;
  194. }
  195. //可能是外部主动设置进来的,统一放在这里添加 subview
  196. if (!_moreContainer.superview)
  197. {
  198. [self addSubview:_moreContainer];
  199. }
  200. }
  201. - (void)setMoreContainer:(UIView *)moreContainer
  202. {
  203. _moreContainer = moreContainer;
  204. [self sizeToFit];
  205. }
  206. //- (YOUPAINIMInputVoiceView *)voiceViewContainer
  207. //{
  208. // if (!_voiceViewContainer) {
  209. // _voiceViewContainer = [[YOUPAINIMInputVoiceView alloc] initWithFrame:CGRectMake(0,_toolBar.nim_height, self.nim_width,216.0f)];
  210. // _voiceViewContainer.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  211. // _voiceViewContainer.hidden = YES;
  212. // }
  213. // return _voiceViewContainer;
  214. //}
  215. - (void)checkVoiceViewContainer{
  216. if (!_voiceViewContainer) {
  217. YOUPAINIMInputVoiceView *voiceContainer = [[YOUPAINIMInputVoiceView alloc] initWithFrame:CGRectMake(0,_toolBar.nim_height, self.nim_width,216.0f)];
  218. voiceContainer.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  219. voiceContainer.hidden = YES;
  220. _voiceViewContainer = voiceContainer;
  221. [_voiceViewContainer.recordBt addTarget:self action:@selector(onTouchRecordBtnDown:) forControlEvents:UIControlEventTouchDown];
  222. [_voiceViewContainer.recordBt addTarget:self action:@selector(onTouchRecordBtnDragInside:) forControlEvents:UIControlEventTouchDragInside];
  223. [_voiceViewContainer.recordBt addTarget:self action:@selector(onTouchRecordBtnDragOutside:) forControlEvents:UIControlEventTouchDragOutside];
  224. [_voiceViewContainer.recordBt addTarget:self action:@selector(onTouchRecordBtnUpInside:) forControlEvents:UIControlEventTouchUpInside];
  225. [_voiceViewContainer.recordBt addTarget:self action:@selector(onTouchRecordBtnUpOutside:) forControlEvents:UIControlEventTouchUpOutside];
  226. }
  227. //可能是外部主动设置进来的,统一放在这里添加 subview
  228. if (!_voiceViewContainer.superview)
  229. {
  230. [self addSubview:_voiceViewContainer];
  231. }
  232. }
  233. - (void)setVoiceViewContainer:(YOUPAINIMInputVoiceView *)voiceViewContainer
  234. {
  235. _voiceViewContainer = voiceViewContainer;
  236. [self sizeToFit];
  237. }
  238. - (void)checkEmoticonContainer
  239. {
  240. if (!_emoticonContainer) {
  241. YOUPAINIMInputEmoticonContainerView *emoticonContainer = [[YOUPAINIMInputEmoticonContainerView alloc] initWithFrame:CGRectZero];
  242. emoticonContainer.nim_size = [emoticonContainer sizeThatFits:CGSizeMake(self.nim_width, CGFLOAT_MAX)];
  243. emoticonContainer.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  244. emoticonContainer.delegate = self;
  245. emoticonContainer.hidden = YES;
  246. emoticonContainer.config = _inputConfig;
  247. _emoticonContainer = emoticonContainer;
  248. }
  249. //可能是外部主动设置进来的,统一放在这里添加 subview
  250. if (!_emoticonContainer.superview)
  251. {
  252. [self addSubview:_emoticonContainer];
  253. }
  254. }
  255. - (void)setEmoticonContainer:(UIView *)emoticonContainer
  256. {
  257. _emoticonContainer = emoticonContainer;
  258. [self sizeToFit];
  259. }
  260. - (void)setRecording:(BOOL)recording
  261. {
  262. if(recording)
  263. {
  264. self.audioRecordIndicator.center = self.superview.center;
  265. [self.superview addSubview:self.audioRecordIndicator];
  266. self.recordPhase = AudioRecordPhaseRecording;
  267. }
  268. else
  269. {
  270. [self.audioRecordIndicator removeFromSuperview];
  271. self.recordPhase = AudioRecordPhaseEnd;
  272. }
  273. _recording = recording;
  274. }
  275. #pragma mark - 外部接口
  276. - (void)setInputTextPlaceHolder:(NSString*)placeHolder
  277. {
  278. [_toolBar setPlaceHolder:placeHolder];
  279. }
  280. - (void)updateAudioRecordTime:(NSTimeInterval)time {
  281. self.audioRecordIndicator.recordTime = time;
  282. // self.voiceViewContainer.recordTime = time;
  283. }
  284. - (void)youpaifupdateVoicePower:(float)power {
  285. }
  286. #pragma mark - private methods
  287. - (void)setFrame:(CGRect)frame
  288. {
  289. CGFloat height = self.frame.size.height;
  290. [super setFrame:frame];
  291. if (frame.size.height != height)
  292. {
  293. [self callDidChangeHeight];
  294. }
  295. }
  296. - (void)callDidChangeHeight
  297. {
  298. if (_inputDelegate && [_inputDelegate respondsToSelector:@selector(youpaifdidChangeInputHeight:)])
  299. {
  300. if (self.status == NIMInputStatusMore || self.status == NIMInputStatusEmoticon || self.status == NIMInputStatusAudio)
  301. {
  302. //这个时候需要一个动画来模拟键盘
  303. [UIView animateWithDuration:0.25 delay:0 options:7 animations:^{
  304. [_inputDelegate youpaifdidChangeInputHeight:self.nim_height];
  305. } completion:nil];
  306. }
  307. else
  308. {
  309. [_inputDelegate youpaifdidChangeInputHeight:self.nim_height];
  310. }
  311. }
  312. }
  313. - (void)layoutSubviews
  314. {
  315. [super layoutSubviews];
  316. //这里不做.语法 get 操作,会提前初始化组件导致卡顿
  317. _moreContainer.nim_top = self.toolBar.nim_bottom;
  318. _emoticonContainer.nim_top = self.toolBar.nim_bottom;
  319. }
  320. #pragma mark - button actions
  321. - (void)onTouchVoiceBtn:(id)sender {
  322. // image change
  323. if (self.status!= NIMInputStatusAudio) {
  324. if ([self.actionDelegate respondsToSelector:@selector(onTapVoiceBtn:)]) {
  325. [self.actionDelegate onTapVoiceBtn:sender];
  326. }
  327. __weak typeof(self) weakSelf = self;
  328. if ([[AVAudioSession sharedInstance] respondsToSelector:@selector(requestRecordPermission:)]) {
  329. [[AVAudioSession sharedInstance] performSelector:@selector(requestRecordPermission:) withObject:^(BOOL granted) {
  330. if (granted) {
  331. dispatch_async(dispatch_get_main_queue(), ^{
  332. [weakSelf refreshStatus:NIMInputStatusAudio];
  333. if (weakSelf.toolBar.showsKeyboard)
  334. {
  335. weakSelf.toolBar.showsKeyboard = NO;
  336. }
  337. [self sizeToFit];
  338. });
  339. }
  340. else {
  341. dispatch_async(dispatch_get_main_queue(), ^{
  342. [[[UIAlertView alloc] initWithTitle:nil
  343. message:@"没有麦克风权限"
  344. delegate:nil
  345. cancelButtonTitle:@"确定"
  346. otherButtonTitles:nil] show];
  347. });
  348. }
  349. }];
  350. }
  351. }
  352. else
  353. {
  354. if ([self.toolBar.inputBarItemTypes containsObject:@(NIMInputBarItemTypeTextAndRecord)])
  355. {
  356. [self refreshStatus:NIMInputStatusText];
  357. self.toolBar.showsKeyboard = YES;
  358. }
  359. }
  360. }
  361. - (IBAction)onTouchRecordBtnDown:(id)sender {
  362. self.recordPhase = AudioRecordPhaseStart;
  363. // self.voiceViewContainer.titleLabel.text = @"";
  364. // self.voiceViewContainer.titleLabel.text = @"松开发送";
  365. [self.voiceViewContainer.recordBt setImage:[UIImage imageNamed:@"vqu_images_vqu_images_IM_im_record_ing"] forState:UIControlStateNormal];;
  366. }
  367. - (IBAction)onTouchRecordBtnUpInside:(id)sender {
  368. // finish Recording
  369. self.recordPhase = AudioRecordPhaseEnd;
  370. self.voiceViewContainer.titleLabel.text = @"按住说话";
  371. self.voiceViewContainer.timeLabel.text = @"";
  372. self.voiceViewContainer.titleLabel.textColor = LZ475A7DColor;
  373. [self.voiceViewContainer.recordBt setImage:[UIImage imageNamed:@"vqu_images_vqu_images_IM_im_record_Voice"] forState:UIControlStateNormal];
  374. }
  375. - (IBAction)onTouchRecordBtnUpOutside:(id)sender {
  376. // cancel Recording
  377. self.recordPhase = AudioRecordPhaseEnd;
  378. self.voiceViewContainer.titleLabel.text = @"按住说话";
  379. self.voiceViewContainer.timeLabel.text = @"";
  380. self.voiceViewContainer.titleLabel.textColor = LZ475A7DColor;
  381. [self.voiceViewContainer.recordBt setImage:[UIImage imageNamed:@"vqu_images_vqu_images_IM_im_record_Voice"] forState:UIControlStateNormal];
  382. }
  383. - (IBAction)onTouchRecordBtnDragInside:(id)sender {
  384. // "手指上滑,取消发送"
  385. // self.voiceViewContainer.titleLabel.text = @"手指上滑,取消发送";
  386. // self.voiceViewContainer.titleLabel.textColor = HexColorFromRGB(0x9F9DA5);
  387. self.voiceViewContainer.timeLabel.textColor = LZ475A7DColor;
  388. self.recordPhase = AudioRecordPhaseRecording;
  389. [self.voiceViewContainer.recordBt setImage:[UIImage imageNamed:@"vqu_images_vqu_images_IM_im_record_ing"] forState:UIControlStateNormal];
  390. }
  391. - (IBAction)onTouchRecordBtnDragOutside:(id)sender {
  392. // "松开手指,取消发送"
  393. // self.voiceViewContainer.titleLabel.text = @"松开手指,取消发送";
  394. // self.voiceViewContainer.titleLabel.textColor = HexColorFromRGB(0x79262C);
  395. // self.voiceViewContainer.timeLabel.textColor = HexColorFromRGB(0xD63641);
  396. self.recordPhase = AudioRecordPhaseCancelling;
  397. [self.voiceViewContainer.recordBt setImage:[UIImage imageNamed:@"vqu_images_vqu_images_IM_im_record_stop"] forState:UIControlStateNormal];;
  398. }
  399. - (void)onTouchCameraBtn:(UIButton*)btn{
  400. if (self.actionDelegate && [self.actionDelegate respondsToSelector:@selector(onCameraClick)]) {
  401. [self.actionDelegate onCameraClick];
  402. }
  403. }
  404. - (void)onTouchSayHiBtn:(UIButton*)btn{
  405. if (self.actionDelegate && [self.actionDelegate respondsToSelector:@selector(onSayHiClick)]) {
  406. [self.actionDelegate onSayHiClick];
  407. }
  408. }
  409. - (void)onTouchPhotoBtn:(UIButton*)btn{
  410. if (self.actionDelegate && [self.actionDelegate respondsToSelector:@selector(onPhotoClick)]) {
  411. [self.actionDelegate onPhotoClick];
  412. }
  413. }
  414. - (void)onTouchGiftBtn:(UIButton*)btn{
  415. if (self.actionDelegate && [self.actionDelegate respondsToSelector:@selector(onGiftClick)]) {
  416. [self.actionDelegate onGiftClick];
  417. }
  418. }
  419. - (void)onTouchVideoBtn:(UIButton*)btn{
  420. if (self.actionDelegate && [self.actionDelegate respondsToSelector:@selector(onVideoClick)]) {
  421. [self.actionDelegate onVideoClick];
  422. }
  423. }
  424. - (void)onTouchRecordBtn:(id)sender{
  425. if (self.status != NIMInputStatusMore)
  426. {
  427. // if ([self.actionDelegate respondsToSelector:@selector(onTapMoreBtn:)]) {
  428. // [self.actionDelegate onTapMoreBtn:sender];
  429. // }
  430. [self checkVoiceViewContainer];
  431. [self bringSubviewToFront:self.voiceViewContainer];
  432. [self.voiceViewContainer setHidden:NO];
  433. [self.emoticonContainer setHidden:YES];
  434. [self refreshStatus:NIMInputStatusMore];
  435. [self sizeToFit];
  436. if (self.toolBar.showsKeyboard)
  437. {
  438. self.toolBar.showsKeyboard = NO;
  439. }
  440. }
  441. else
  442. {
  443. [self refreshStatus:NIMInputStatusText];
  444. self.toolBar.showsKeyboard = YES;
  445. }
  446. }
  447. - (void)onTouchEmoticonBtn:(id)sender
  448. {
  449. if (self.status != NIMInputStatusEmoticon) {
  450. if ([self.actionDelegate respondsToSelector:@selector(onTapEmoticonBtn:)]) {
  451. [self.actionDelegate onTapEmoticonBtn:sender];
  452. }
  453. [self checkEmoticonContainer];
  454. [self bringSubviewToFront:self.emoticonContainer];
  455. [self.emoticonContainer setHidden:NO];
  456. [self.voiceViewContainer setHidden:YES];
  457. [self refreshStatus:NIMInputStatusEmoticon];
  458. [self sizeToFit];
  459. if (self.toolBar.showsKeyboard)
  460. {
  461. self.toolBar.showsKeyboard = NO;
  462. }
  463. }
  464. else
  465. {
  466. [self refreshStatus:NIMInputStatusText];
  467. self.toolBar.showsKeyboard = YES;
  468. }
  469. }
  470. - (void)onTouchMoreBtn:(id)sender {
  471. if (self.status != NIMInputStatusMore)
  472. {
  473. if ([self.actionDelegate respondsToSelector:@selector(onTapMoreBtn:)]) {
  474. [self.actionDelegate onTapMoreBtn:sender];
  475. }
  476. [self checkMoreContainer];
  477. [self bringSubviewToFront:self.moreContainer];
  478. [self.moreContainer setHidden:NO];
  479. [self.emoticonContainer setHidden:YES];
  480. [self refreshStatus:NIMInputStatusMore];
  481. [self sizeToFit];
  482. if (self.toolBar.showsKeyboard)
  483. {
  484. self.toolBar.showsKeyboard = NO;
  485. }
  486. }
  487. else
  488. {
  489. [self refreshStatus:NIMInputStatusText];
  490. self.toolBar.showsKeyboard = YES;
  491. }
  492. }
  493. - (BOOL)endEditing:(BOOL)force
  494. {
  495. BOOL endEditing = [super endEditing:force];
  496. if (!self.toolBar.showsKeyboard) {
  497. UIViewAnimationCurve curve = UIViewAnimationCurveEaseInOut;
  498. void(^animations)(void) = ^{
  499. [self refreshStatus:NIMInputStatusText];
  500. [self sizeToFit];
  501. if (self.inputDelegate && [self.inputDelegate respondsToSelector:@selector(youpaifdidChangeInputHeight:)]) {
  502. [self.inputDelegate youpaifdidChangeInputHeight:self.nim_height];
  503. }
  504. };
  505. NSTimeInterval duration = 0.25;
  506. [UIView animateWithDuration:duration delay:0.0f options:(curve << 16 | UIViewAnimationOptionBeginFromCurrentState) animations:animations completion:nil];
  507. }
  508. return endEditing;
  509. }
  510. #pragma mark - NIMInputToolBarDelegate
  511. - (BOOL)textViewShouldBeginEditing
  512. {
  513. [self refreshStatus:NIMInputStatusText];
  514. return YES;
  515. }
  516. - (BOOL)youpaifshouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
  517. {
  518. if ([text isEqualToString:@"\n"])
  519. {
  520. [self youpaifdidPressSend:nil];
  521. return NO;
  522. }
  523. if ([text isEqualToString:@""] && range.length == 1 )
  524. {
  525. //非选择删除
  526. return [self onTextDelete];
  527. }
  528. if ([self shouldCheckAt])
  529. {
  530. // @ 功能
  531. [self checkAt:text];
  532. }
  533. NSString *str = [self.toolBar.contentText stringByAppendingString:text];
  534. if (str.length > self.maxTextLength)
  535. {
  536. return NO;
  537. }
  538. return YES;
  539. }
  540. - (BOOL)shouldCheckAt
  541. {
  542. BOOL disable = NO;
  543. if ([self.inputConfig respondsToSelector:@selector(disableAt)])
  544. {
  545. disable = [self.inputConfig disableAt];
  546. }
  547. return !disable;
  548. }
  549. - (void)checkAt:(NSString *)text
  550. {
  551. if ([text isEqualToString:NIMInputAtStartChar]) {
  552. switch (self.session.sessionType) {
  553. case NIMSessionTypeTeam:{
  554. NIMContactTeamMemberSelectConfig *config = [[NIMContactTeamMemberSelectConfig alloc] init];
  555. if ([self.inputConfig respondsToSelector:@selector(enableRobot)])
  556. {
  557. config.enableRobot = [self.inputConfig enableRobot];
  558. }
  559. else
  560. {
  561. config.enableRobot = YES;
  562. }
  563. config.needMutiSelected = NO;
  564. config.teamId = self.session.sessionId;
  565. config.filterIds = @[[NIMSDK sharedSDK].loginManager.currentAccount];
  566. NIMContactSelectViewController *vc = [[NIMContactSelectViewController alloc] initWithConfig:config];
  567. vc.delegate = self;
  568. dispatch_async(dispatch_get_main_queue(), ^{
  569. [vc show];
  570. });
  571. }
  572. break;
  573. case NIMSessionTypeP2P:
  574. case NIMSessionTypeChatroom:{
  575. if (([self.inputConfig respondsToSelector:@selector(enableRobot)] && self.inputConfig.enableRobot) || [NIMSDK sharedSDK].isUsingDemoAppKey)
  576. {
  577. NIMContactRobotSelectConfig *config = [[NIMContactRobotSelectConfig alloc] init];
  578. config.needMutiSelected = NO;
  579. NIMContactSelectViewController *vc = [[NIMContactSelectViewController alloc] initWithConfig:config];
  580. vc.delegate = self;
  581. dispatch_async(dispatch_get_main_queue(), ^{
  582. [vc show];
  583. });
  584. }
  585. }
  586. break;
  587. default:
  588. break;
  589. }
  590. }
  591. }
  592. - (void)textViewDidChange
  593. {
  594. if (self.actionDelegate && [self.actionDelegate respondsToSelector:@selector(onTextChanged:)])
  595. {
  596. [self.actionDelegate onTextChanged:self];
  597. }
  598. }
  599. - (void)youpaiftoolBarDidChangeHeight:(CGFloat)height
  600. {
  601. [self sizeToFit];
  602. }
  603. #pragma mark - NIMContactSelectDelegate
  604. - (void)didFinishedSelect:(NSArray *)selectedContacts
  605. {
  606. NSMutableString *str = [[NSMutableString alloc] initWithString:@""];
  607. NIMKitInfoFetchOption *option = [[NIMKitInfoFetchOption alloc] init];
  608. option.session = self.session;
  609. option.forbidaAlias = YES;
  610. for (NSString *uid in selectedContacts) {
  611. NSString *nick = [[NIMKit sharedKit].provider infoByUser:uid option:option].showName;
  612. [str appendString:nick];
  613. [str appendString:NIMInputAtEndChar];
  614. if (![selectedContacts.lastObject isEqualToString:uid]) {
  615. [str appendString:NIMInputAtStartChar];
  616. }
  617. NIMInputAtItem *item = [[NIMInputAtItem alloc] init];
  618. item.uid = uid;
  619. item.name = nick;
  620. [self.atCache addAtItem:item];
  621. }
  622. [self.toolBar insertText:str];
  623. }
  624. #pragma mark - InputEmoticonProtocol
  625. - (void)selectedEmoticon:(NSString*)emoticonID catalog:(NSString*)emotCatalogID description:(NSString *)description{
  626. if (!emotCatalogID) { //删除键
  627. [self onTextDelete];
  628. }else{
  629. if ([emotCatalogID isEqualToString:NIMKit_EmojiCatalog]) {
  630. [self.toolBar insertText:description];
  631. }else{
  632. //发送贴图消息
  633. if ([self.actionDelegate respondsToSelector:@selector(onSelectChartlet:catalog:)]) {
  634. [self.actionDelegate onSelectChartlet:emoticonID catalog:emotCatalogID];
  635. }
  636. }
  637. }
  638. }
  639. - (void)youpaifdidPressSend:(id)sender{
  640. if ([self.actionDelegate respondsToSelector:@selector(onSendText:atUsers:)] && [self.toolBar.contentText length] > 0) {
  641. NSString *sendText = self.toolBar.contentText;
  642. [self.actionDelegate onSendText:sendText atUsers:[self.atCache youpaifallAtUid:sendText]];
  643. [self.atCache clean];
  644. self.toolBar.contentText = @"";
  645. [self.toolBar layoutIfNeeded];
  646. }
  647. }
  648. - (BOOL)onTextDelete
  649. {
  650. NSRange range = [self delRangeForEmoticon];
  651. if (range.length == 1)
  652. {
  653. //删的不是表情,可能是@
  654. NIMInputAtItem *item = [self delRangeForAt];
  655. if (item) {
  656. range = item.range;
  657. }
  658. }
  659. if (range.length == 1) {
  660. //自动删除
  661. return YES;
  662. }
  663. [self.toolBar deleteText:range];
  664. return NO;
  665. }
  666. - (NSRange)delRangeForEmoticon
  667. {
  668. NSString *text = self.toolBar.contentText;
  669. NSRange range = [self rangeForPrefix:@"[" suffix:@"]"];
  670. NSRange selectedRange = [self.toolBar selectedRange];
  671. if (range.length > 1)
  672. {
  673. NSString *name = [text substringWithRange:range];
  674. NIMInputEmoticon *icon = [[YOUPAINIMInputEmoticonManager sharedManager] emoticonByTag:name];
  675. range = icon? range : NSMakeRange(selectedRange.location - 1, 1);
  676. }
  677. return range;
  678. }
  679. - (NIMInputAtItem *)delRangeForAt
  680. {
  681. NSString *text = self.toolBar.contentText;
  682. NSRange range = [self rangeForPrefix:NIMInputAtStartChar suffix:NIMInputAtEndChar];
  683. NSRange selectedRange = [self.toolBar selectedRange];
  684. NIMInputAtItem *item = nil;
  685. if (range.length > 1)
  686. {
  687. NSString *name = [text substringWithRange:range];
  688. NSString *set = [NIMInputAtStartChar stringByAppendingString:NIMInputAtEndChar];
  689. name = [name stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:set]];
  690. item = [self.atCache item:name];
  691. range = item? range : NSMakeRange(selectedRange.location - 1, 1);
  692. }
  693. item.range = range;
  694. return item;
  695. }
  696. - (NSRange)rangeForPrefix:(NSString *)prefix suffix:(NSString *)suffix
  697. {
  698. NSString *text = self.toolBar.contentText;
  699. NSRange range = [self.toolBar selectedRange];
  700. NSString *selectedText = range.length ? [text substringWithRange:range] : text;
  701. NSInteger endLocation = range.location;
  702. if (endLocation <= 0)
  703. {
  704. return NSMakeRange(NSNotFound, 0);
  705. }
  706. NSInteger index = -1;
  707. if ([selectedText hasSuffix:suffix]) {
  708. //往前搜最多20个字符,一般来讲是够了...
  709. NSInteger p = 20;
  710. for (NSInteger i = endLocation; i >= endLocation - p && i-1 >= 0 ; i--)
  711. {
  712. NSRange subRange = NSMakeRange(i - 1, 1);
  713. NSString *subString = [text substringWithRange:subRange];
  714. if ([subString compare:prefix] == NSOrderedSame)
  715. {
  716. index = i - 1;
  717. break;
  718. }
  719. }
  720. }
  721. return index == -1? NSMakeRange(endLocation - 1, 1) : NSMakeRange(index, endLocation - index);
  722. }
  723. @end