New file |
| | |
| | | /************************************************************ |
| | | * * Hyphenate CONFIDENTIAL |
| | | * __________________ |
| | | * Copyright (C) 2016 Hyphenate Inc. All rights reserved. |
| | | * |
| | | * NOTICE: All information contained herein is, and remains |
| | | * the property of Hyphenate Inc. |
| | | * Dissemination of this information or reproduction of this material |
| | | * is strictly forbidden unless prior written permission is obtained |
| | | * from Hyphenate Inc. |
| | | */ |
| | | |
| | | #import "EaseChatToolbar.h" |
| | | |
| | | #import "EaseFaceView.h" |
| | | #import "EaseEmoji.h" |
| | | #import "EaseEmotionEscape.h" |
| | | #import "EaseEmotionManager.h" |
| | | #import "EaseLocalDefine.h" |
| | | |
| | | @interface EaseChatToolbar()<UITextViewDelegate, EMFaceDelegate> |
| | | |
| | | @property (nonatomic) CGFloat version; |
| | | @property (strong, nonatomic) NSMutableArray *leftItems; |
| | | @property (strong, nonatomic) NSMutableArray *rightItems; |
| | | @property (strong, nonatomic) UIImageView *toolbarBackgroundImageView; |
| | | @property (strong, nonatomic) UIImageView *backgroundImageView; |
| | | @property (nonatomic) BOOL isShowButtomView; |
| | | @property (strong, nonatomic) UIView *activityButtomView; |
| | | @property (strong, nonatomic) UIView *toolbarView; |
| | | @property (strong, nonatomic) UIButton *recordButton; |
| | | @property (strong, nonatomic) UIButton *moreButton; |
| | | @property (strong, nonatomic) UIButton *faceButton; |
| | | @property (nonatomic) CGFloat previousTextViewContentHeight;//上一次inputTextView的contentSize.height |
| | | @property (nonatomic) NSLayoutConstraint *inputViewWidthItemsLeftConstraint; |
| | | @property (nonatomic) NSLayoutConstraint *inputViewWidthoutItemsLeftConstraint; |
| | | |
| | | @end |
| | | |
| | | @implementation EaseChatToolbar |
| | | |
| | | @synthesize faceView = _faceView; |
| | | @synthesize moreView = _moreView; |
| | | @synthesize recordView = _recordView; |
| | | |
| | | - (instancetype)initWithFrame:(CGRect)frame |
| | | { |
| | | self = [self initWithFrame:frame horizontalPadding:8 verticalPadding:5 inputViewMinHeight:36 inputViewMaxHeight:150 type:EMChatToolbarTypeGroup]; |
| | | if (self) { |
| | | |
| | | } |
| | | |
| | | return self; |
| | | } |
| | | |
| | | - (instancetype)initWithFrame:(CGRect)frame |
| | | type:(EMChatToolbarType)type |
| | | { |
| | | self = [self initWithFrame:frame horizontalPadding:8 verticalPadding:5 inputViewMinHeight:36 inputViewMaxHeight:150 type:type]; |
| | | if (self) { |
| | | |
| | | } |
| | | |
| | | return self; |
| | | } |
| | | |
| | | - (instancetype)initWithFrame:(CGRect)frame |
| | | horizontalPadding:(CGFloat)horizontalPadding |
| | | verticalPadding:(CGFloat)verticalPadding |
| | | inputViewMinHeight:(CGFloat)inputViewMinHeight |
| | | inputViewMaxHeight:(CGFloat)inputViewMaxHeight |
| | | type:(EMChatToolbarType)type |
| | | { |
| | | if (frame.size.height < (verticalPadding * 2 + inputViewMinHeight)) { |
| | | frame.size.height = verticalPadding * 2 + inputViewMinHeight; |
| | | } |
| | | self = [super initWithFrame:frame]; |
| | | if (self) { |
| | | self.accessibilityIdentifier = @"chatbar"; |
| | | |
| | | _horizontalPadding = horizontalPadding; |
| | | _verticalPadding = verticalPadding; |
| | | _inputViewMinHeight = inputViewMinHeight; |
| | | _inputViewMaxHeight = inputViewMaxHeight; |
| | | _chatBarType = type; |
| | | |
| | | _leftItems = [NSMutableArray array]; |
| | | _rightItems = [NSMutableArray array]; |
| | | _version = [[[UIDevice currentDevice] systemVersion] floatValue]; |
| | | _activityButtomView = nil; |
| | | _isShowButtomView = NO; |
| | | |
| | | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(chatKeyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil]; |
| | | |
| | | [self _setupSubviews]; |
| | | } |
| | | return self; |
| | | } |
| | | |
| | | #pragma mark - setup subviews |
| | | |
| | | /*! |
| | | @method |
| | | @brief 加载视图 |
| | | @discussion |
| | | @result |
| | | */ |
| | | - (void)_setupSubviews |
| | | { |
| | | //backgroundImageView |
| | | _backgroundImageView = [[UIImageView alloc] initWithFrame:self.bounds]; |
| | | _backgroundImageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; |
| | | _backgroundImageView.backgroundColor = [UIColor clearColor]; |
| | | _backgroundImageView.image = [[UIImage easeImageNamed:@"EaseUIResource.bundle/messageToolbarBg"] stretchableImageWithLeftCapWidth:0.5 topCapHeight:10]; |
| | | [self addSubview:_backgroundImageView]; |
| | | |
| | | //toolbar |
| | | _toolbarView = [[UIView alloc] initWithFrame:self.bounds]; |
| | | _toolbarView.backgroundColor = [UIColor clearColor]; |
| | | [self addSubview:_toolbarView]; |
| | | |
| | | _toolbarBackgroundImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, _toolbarView.frame.size.width, _toolbarView.frame.size.height)]; |
| | | _toolbarBackgroundImageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; |
| | | _toolbarBackgroundImageView.backgroundColor = [UIColor clearColor]; |
| | | [_toolbarView addSubview:_toolbarBackgroundImageView]; |
| | | |
| | | //input textview |
| | | _inputTextView = [[EaseTextView alloc] initWithFrame:CGRectMake(self.horizontalPadding, self.verticalPadding, self.frame.size.width - self.verticalPadding * 2, self.frame.size.height - self.verticalPadding * 2)]; |
| | | _inputTextView.autoresizingMask = UIViewAutoresizingFlexibleHeight; |
| | | _inputTextView.scrollEnabled = YES; |
| | | _inputTextView.returnKeyType = UIReturnKeySend; |
| | | _inputTextView.enablesReturnKeyAutomatically = YES; // UITextView内部判断send按钮是否可以用 |
| | | _inputTextView.placeHolder = NSEaseLocalizedString(@"message.toolBar.inputPlaceHolder", @"input a new message"); |
| | | _inputTextView.delegate = self; |
| | | _inputTextView.backgroundColor = [UIColor clearColor]; |
| | | _inputTextView.layer.borderColor = [UIColor colorWithWhite:0.8f alpha:1.0f].CGColor; |
| | | _inputTextView.layer.borderWidth = 0.65f; |
| | | _inputTextView.layer.cornerRadius = 6.0f; |
| | | _previousTextViewContentHeight = [self _getTextViewContentH:_inputTextView]; |
| | | [_toolbarView addSubview:_inputTextView]; |
| | | |
| | | //change input type |
| | | UIButton *styleChangeButton = [[UIButton alloc] init]; |
| | | styleChangeButton.accessibilityIdentifier = @"style"; |
| | | styleChangeButton.autoresizingMask = UIViewAutoresizingFlexibleTopMargin; |
| | | [styleChangeButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_record"] forState:UIControlStateNormal]; |
| | | [styleChangeButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_keyboard"] forState:UIControlStateSelected]; |
| | | [styleChangeButton addTarget:self action:@selector(styleButtonAction:) forControlEvents:UIControlEventTouchUpInside]; |
| | | |
| | | EaseChatToolbarItem *styleItem = [[EaseChatToolbarItem alloc] initWithButton:styleChangeButton withView:nil]; |
| | | [self setInputViewLeftItems:@[styleItem]]; |
| | | |
| | | //record |
| | | self.recordButton = [[UIButton alloc] initWithFrame:self.inputTextView.frame]; |
| | | self.recordButton.accessibilityIdentifier = @"record"; |
| | | self.recordButton.titleLabel.font = [UIFont systemFontOfSize:15.0]; |
| | | [self.recordButton setTitleColor:[UIColor darkGrayColor] forState:UIControlStateNormal]; |
| | | [self.recordButton setBackgroundImage:[[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_recordBg"] stretchableImageWithLeftCapWidth:10 topCapHeight:10] forState:UIControlStateNormal]; |
| | | [self.recordButton setBackgroundImage:[[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_recordSelectedBg"] stretchableImageWithLeftCapWidth:10 topCapHeight:10] forState:UIControlStateHighlighted]; |
| | | [self.recordButton setTitle:kTouchToRecord forState:UIControlStateNormal]; |
| | | [self.recordButton setTitle:kTouchToFinish forState:UIControlStateHighlighted]; |
| | | self.recordButton.hidden = YES; |
| | | [self.recordButton addTarget:self action:@selector(recordButtonTouchDown) forControlEvents:UIControlEventTouchDown]; |
| | | [self.recordButton addTarget:self action:@selector(recordButtonTouchUpOutside) forControlEvents:UIControlEventTouchUpOutside]; |
| | | [self.recordButton addTarget:self action:@selector(recordButtonTouchUpInside) forControlEvents:UIControlEventTouchUpInside]; |
| | | [self.recordButton addTarget:self action:@selector(recordDragOutside) forControlEvents:UIControlEventTouchDragExit]; |
| | | [self.recordButton addTarget:self action:@selector(recordDragInside) forControlEvents:UIControlEventTouchDragEnter]; |
| | | self.recordButton.hidden = YES; |
| | | [self.toolbarView addSubview:self.recordButton]; |
| | | |
| | | //emoji |
| | | self.faceButton = [[UIButton alloc] init]; |
| | | self.faceButton.accessibilityIdentifier = @"face"; |
| | | self.faceButton.autoresizingMask = UIViewAutoresizingFlexibleTopMargin; |
| | | [self.faceButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_face"] forState:UIControlStateNormal]; |
| | | [self.faceButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_faceSelected"] forState:UIControlStateHighlighted]; |
| | | [self.faceButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_keyboard"] forState:UIControlStateSelected]; |
| | | [self.faceButton addTarget:self action:@selector(faceButtonAction:) forControlEvents:UIControlEventTouchUpInside]; |
| | | EaseChatToolbarItem *faceItem = [[EaseChatToolbarItem alloc] initWithButton:self.faceButton withView:self.faceView]; |
| | | |
| | | //more |
| | | self.moreButton = [[UIButton alloc] init]; |
| | | self.moreButton.accessibilityIdentifier = @"more"; |
| | | self.moreButton.autoresizingMask = UIViewAutoresizingFlexibleTopMargin; |
| | | [self.moreButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_more"] forState:UIControlStateNormal]; |
| | | [self.moreButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_moreSelected"] forState:UIControlStateHighlighted]; |
| | | [self.moreButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_keyboard"] forState:UIControlStateSelected]; |
| | | [self.moreButton addTarget:self action:@selector(moreButtonAction:) forControlEvents:UIControlEventTouchUpInside]; |
| | | EaseChatToolbarItem *moreItem = [[EaseChatToolbarItem alloc] initWithButton:self.moreButton withView:self.moreView]; |
| | | |
| | | [self setInputViewRightItems:@[faceItem, moreItem]]; |
| | | } |
| | | |
| | | - (void)dealloc |
| | | { |
| | | [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillChangeFrameNotification object:nil]; |
| | | |
| | | _delegate = nil; |
| | | _inputTextView.delegate = nil; |
| | | _inputTextView = nil; |
| | | } |
| | | |
| | | #pragma mark - getter |
| | | |
| | | - (UIView *)recordView |
| | | { |
| | | if (_recordView == nil) { |
| | | _recordView = [[EaseRecordView alloc] initWithFrame:CGRectMake(90, 130, 140, 140)]; |
| | | } |
| | | |
| | | return _recordView; |
| | | } |
| | | |
| | | - (UIView *)faceView |
| | | { |
| | | if (_faceView == nil) { |
| | | _faceView = [[EaseFaceView alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(_toolbarView.frame), self.frame.size.width, 180)]; |
| | | [(EaseFaceView *)_faceView setDelegate:self]; |
| | | _faceView.backgroundColor = [UIColor colorWithRed:240 / 255.0 green:242 / 255.0 blue:247 / 255.0 alpha:1.0]; |
| | | _faceView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin; |
| | | } |
| | | |
| | | return _faceView; |
| | | } |
| | | |
| | | - (UIView *)moreView |
| | | { |
| | | if (_moreView == nil) { |
| | | _moreView = [[EaseChatBarMoreView alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(_toolbarView.frame), self.frame.size.width, 80) type:self.chatBarType]; |
| | | _moreView.backgroundColor = [UIColor colorWithRed:240 / 255.0 green:242 / 255.0 blue:247 / 255.0 alpha:1.0]; |
| | | _moreView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin; |
| | | } |
| | | |
| | | return _moreView; |
| | | } |
| | | |
| | | #pragma mark - setter |
| | | |
| | | - (void)setDelegate:(id)delegate |
| | | { |
| | | _delegate = delegate; |
| | | if ([_moreView isKindOfClass:[EaseChatBarMoreView class]]) { |
| | | [(EaseChatBarMoreView *)_moreView setDelegate:delegate]; |
| | | } |
| | | } |
| | | |
| | | - (void)setRecordView:(UIView *)recordView |
| | | { |
| | | if(_recordView != recordView){ |
| | | _recordView = recordView; |
| | | } |
| | | } |
| | | |
| | | - (void)setMoreView:(UIView *)moreView |
| | | { |
| | | if (_moreView != moreView) { |
| | | _moreView = moreView; |
| | | |
| | | for (EaseChatToolbarItem *item in self.rightItems) { |
| | | if (item.button == self.moreButton) { |
| | | item.button2View = _moreView; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | - (void)setFaceView:(UIView *)faceView |
| | | { |
| | | if (_faceView != faceView) { |
| | | _faceView = faceView; |
| | | |
| | | for (EaseChatToolbarItem *item in self.rightItems) { |
| | | if (item.button == self.faceButton) { |
| | | item.button2View = _faceView; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | - (NSArray*)inputViewLeftItems |
| | | { |
| | | return self.leftItems; |
| | | } |
| | | |
| | | /*! |
| | | @method |
| | | @brief 设置toolBar左侧菜单选项 |
| | | @discussion |
| | | @param inputViewLeftItems 左侧选项 |
| | | @result |
| | | */ |
| | | - (void)setInputViewLeftItems:(NSArray *)inputViewLeftItems |
| | | { |
| | | for (EaseChatToolbarItem *item in self.leftItems) { |
| | | [item.button removeFromSuperview]; |
| | | [item.button2View removeFromSuperview]; |
| | | } |
| | | [self.leftItems removeAllObjects]; |
| | | |
| | | CGFloat oX = self.horizontalPadding; |
| | | CGFloat itemHeight = self.toolbarView.frame.size.height - self.verticalPadding * 2; |
| | | for (id item in inputViewLeftItems) { |
| | | if ([item isKindOfClass:[EaseChatToolbarItem class]]) { |
| | | EaseChatToolbarItem *chatItem = (EaseChatToolbarItem *)item; |
| | | if (chatItem.button) { |
| | | CGRect itemFrame = chatItem.button.frame; |
| | | if (itemFrame.size.height == 0) { |
| | | itemFrame.size.height = itemHeight; |
| | | } |
| | | |
| | | if (itemFrame.size.width == 0) { |
| | | itemFrame.size.width = itemFrame.size.height; |
| | | } |
| | | |
| | | itemFrame.origin.x = oX; |
| | | itemFrame.origin.y = (self.toolbarView.frame.size.height - itemFrame.size.height) / 2; |
| | | chatItem.button.frame = itemFrame; |
| | | oX += (itemFrame.size.width + self.horizontalPadding); |
| | | |
| | | [self.toolbarView addSubview:chatItem.button]; |
| | | [self.leftItems addObject:chatItem]; |
| | | } |
| | | } |
| | | } |
| | | |
| | | CGRect inputFrame = self.inputTextView.frame; |
| | | CGFloat value = inputFrame.origin.x - oX; |
| | | inputFrame.origin.x = oX; |
| | | inputFrame.size.width += value; |
| | | self.inputTextView.frame = inputFrame; |
| | | |
| | | CGRect recordFrame = self.recordButton.frame; |
| | | recordFrame.origin.x = inputFrame.origin.x; |
| | | recordFrame.size.width = inputFrame.size.width; |
| | | self.recordButton.frame = recordFrame; |
| | | } |
| | | |
| | | - (NSArray*)inputViewRightItems |
| | | { |
| | | return self.rightItems; |
| | | } |
| | | |
| | | /*! |
| | | @method |
| | | @brief 设置toolBar右侧菜单选项 |
| | | @discussion |
| | | @param inputViewLeftItems 右侧选项 |
| | | @result |
| | | */ |
| | | - (void)setInputViewRightItems:(NSArray *)inputViewRightItems |
| | | { |
| | | for (EaseChatToolbarItem *item in self.rightItems) { |
| | | [item.button removeFromSuperview]; |
| | | [item.button2View removeFromSuperview]; |
| | | } |
| | | [self.rightItems removeAllObjects]; |
| | | |
| | | CGFloat oMaxX = self.toolbarView.frame.size.width - self.horizontalPadding; |
| | | CGFloat itemHeight = self.toolbarView.frame.size.height - self.verticalPadding * 2; |
| | | if ([inputViewRightItems count] > 0) { |
| | | for (NSInteger i = (inputViewRightItems.count - 1); i >= 0; i--) { |
| | | id item = [inputViewRightItems objectAtIndex:i]; |
| | | if ([item isKindOfClass:[EaseChatToolbarItem class]]) { |
| | | EaseChatToolbarItem *chatItem = (EaseChatToolbarItem *)item; |
| | | if (chatItem.button) { |
| | | CGRect itemFrame = chatItem.button.frame; |
| | | if (itemFrame.size.height == 0) { |
| | | itemFrame.size.height = itemHeight; |
| | | } |
| | | |
| | | if (itemFrame.size.width == 0) { |
| | | itemFrame.size.width = itemFrame.size.height; |
| | | } |
| | | |
| | | oMaxX -= itemFrame.size.width; |
| | | itemFrame.origin.x = oMaxX; |
| | | itemFrame.origin.y = (self.toolbarView.frame.size.height - itemFrame.size.height) / 2; |
| | | chatItem.button.frame = itemFrame; |
| | | oMaxX -= self.horizontalPadding; |
| | | |
| | | [self.toolbarView addSubview:chatItem.button]; |
| | | [self.rightItems addObject:item]; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | CGRect inputFrame = self.inputTextView.frame; |
| | | CGFloat value = oMaxX - CGRectGetMaxX(inputFrame); |
| | | inputFrame.size.width += value; |
| | | self.inputTextView.frame = inputFrame; |
| | | |
| | | CGRect recordFrame = self.recordButton.frame; |
| | | recordFrame.origin.x = inputFrame.origin.x; |
| | | recordFrame.size.width = inputFrame.size.width; |
| | | self.recordButton.frame = recordFrame; |
| | | } |
| | | |
| | | #pragma mark - private input view |
| | | |
| | | /*! |
| | | @method |
| | | @brief 获取textView的高度(实际为textView的contentSize的高度) |
| | | @discussion |
| | | @param textView 文本框 |
| | | @result |
| | | */ |
| | | - (CGFloat)_getTextViewContentH:(UITextView *)textView |
| | | { |
| | | if (self.version >= 7.0) |
| | | { |
| | | return ceilf([textView sizeThatFits:textView.frame.size].height); |
| | | } else { |
| | | return textView.contentSize.height; |
| | | } |
| | | } |
| | | |
| | | /*! |
| | | @method |
| | | @brief 通过传入的toHeight,跳转toolBar的高度 |
| | | @discussion |
| | | @param toHeight |
| | | @result |
| | | */ |
| | | - (void)_willShowInputTextViewToHeight:(CGFloat)toHeight |
| | | { |
| | | if (toHeight < self.inputViewMinHeight) { |
| | | toHeight = self.inputViewMinHeight; |
| | | } |
| | | if (toHeight > self.inputViewMaxHeight) { |
| | | toHeight = self.inputViewMaxHeight; |
| | | } |
| | | |
| | | if (toHeight == _previousTextViewContentHeight) |
| | | { |
| | | return; |
| | | } |
| | | else{ |
| | | CGFloat changeHeight = toHeight - _previousTextViewContentHeight; |
| | | |
| | | CGRect rect = self.frame; |
| | | rect.size.height += changeHeight; |
| | | rect.origin.y -= changeHeight; |
| | | self.frame = rect; |
| | | |
| | | rect = self.toolbarView.frame; |
| | | rect.size.height += changeHeight; |
| | | self.toolbarView.frame = rect; |
| | | |
| | | if (self.version < 7.0) { |
| | | [self.inputTextView setContentOffset:CGPointMake(0.0f, (self.inputTextView.contentSize.height - self.inputTextView.frame.size.height) / 2) animated:YES]; |
| | | } |
| | | _previousTextViewContentHeight = toHeight; |
| | | |
| | | if (_delegate && [_delegate respondsToSelector:@selector(chatToolbarDidChangeFrameToHeight:)]) { |
| | | [_delegate chatToolbarDidChangeFrameToHeight:self.frame.size.height]; |
| | | } |
| | | } |
| | | } |
| | | |
| | | #pragma mark - private bottom view |
| | | |
| | | /*! |
| | | @method |
| | | @brief 调整toolBar的高度 |
| | | @discussion |
| | | @param bottomHeight 底部菜单的高度 |
| | | @result |
| | | */ |
| | | - (void)_willShowBottomHeight:(CGFloat)bottomHeight |
| | | { |
| | | CGRect fromFrame = self.frame; |
| | | CGFloat toHeight = self.toolbarView.frame.size.height + bottomHeight; |
| | | CGRect toFrame = CGRectMake(fromFrame.origin.x, fromFrame.origin.y + (fromFrame.size.height - toHeight), fromFrame.size.width, toHeight); |
| | | |
| | | if(bottomHeight == 0 && self.frame.size.height == self.toolbarView.frame.size.height) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | if (bottomHeight == 0) { |
| | | self.isShowButtomView = NO; |
| | | } |
| | | else{ |
| | | self.isShowButtomView = YES; |
| | | } |
| | | |
| | | self.frame = toFrame; |
| | | |
| | | if (_delegate && [_delegate respondsToSelector:@selector(chatToolbarDidChangeFrameToHeight:)]) { |
| | | [_delegate chatToolbarDidChangeFrameToHeight:toHeight]; |
| | | } |
| | | } |
| | | |
| | | /*! |
| | | @method |
| | | @brief 切换菜单视图 |
| | | @discussion |
| | | @param bottomView 菜单视图 |
| | | @result |
| | | */ |
| | | - (void)_willShowBottomView:(UIView *)bottomView |
| | | { |
| | | if (![self.activityButtomView isEqual:bottomView]) { |
| | | CGFloat bottomHeight = bottomView ? bottomView.frame.size.height : 0; |
| | | [self _willShowBottomHeight:bottomHeight]; |
| | | |
| | | if (bottomView) { |
| | | CGRect rect = bottomView.frame; |
| | | rect.origin.y = CGRectGetMaxY(self.toolbarView.frame); |
| | | bottomView.frame = rect; |
| | | [self addSubview:bottomView]; |
| | | } |
| | | |
| | | if (self.activityButtomView) { |
| | | [self.activityButtomView removeFromSuperview]; |
| | | } |
| | | self.activityButtomView = bottomView; |
| | | } |
| | | } |
| | | |
| | | - (void)_willShowKeyboardFromFrame:(CGRect)beginFrame toFrame:(CGRect)toFrame |
| | | { |
| | | if (beginFrame.origin.y == [[UIScreen mainScreen] bounds].size.height) |
| | | { |
| | | [self _willShowBottomHeight:toFrame.size.height - iPhoneX_BOTTOM_HEIGHT]; |
| | | if (self.activityButtomView) { |
| | | [self.activityButtomView removeFromSuperview]; |
| | | } |
| | | self.activityButtomView = nil; |
| | | } |
| | | else if (toFrame.origin.y == [[UIScreen mainScreen] bounds].size.height) |
| | | { |
| | | [self _willShowBottomHeight:0]; |
| | | } |
| | | else{ |
| | | [self _willShowBottomHeight:toFrame.size.height - iPhoneX_BOTTOM_HEIGHT]; |
| | | } |
| | | } |
| | | |
| | | #pragma mark - UITextViewDelegate |
| | | |
| | | - (BOOL)textViewShouldBeginEditing:(UITextView *)textView |
| | | { |
| | | if ([self.delegate respondsToSelector:@selector(inputTextViewWillBeginEditing:)]) { |
| | | [self.delegate inputTextViewWillBeginEditing:self.inputTextView]; |
| | | } |
| | | |
| | | for (EaseChatToolbarItem *item in self.leftItems) { |
| | | item.button.selected = NO; |
| | | } |
| | | |
| | | for (EaseChatToolbarItem *item in self.rightItems) { |
| | | item.button.selected = NO; |
| | | } |
| | | |
| | | return YES; |
| | | } |
| | | |
| | | - (void)textViewDidBeginEditing:(UITextView *)textView |
| | | { |
| | | [textView becomeFirstResponder]; |
| | | |
| | | if ([self.delegate respondsToSelector:@selector(inputTextViewDidBeginEditing:)]) { |
| | | [self.delegate inputTextViewDidBeginEditing:self.inputTextView]; |
| | | } |
| | | } |
| | | |
| | | - (void)textViewDidEndEditing:(UITextView *)textView |
| | | { |
| | | [textView resignFirstResponder]; |
| | | } |
| | | |
| | | - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text |
| | | { |
| | | if ([text isEqualToString:@"\n"]) { |
| | | if ([self.delegate respondsToSelector:@selector(didSendText:)]) { |
| | | [self.delegate didSendText:textView.text]; |
| | | self.inputTextView.text = @""; |
| | | [self _willShowInputTextViewToHeight:[self _getTextViewContentH:self.inputTextView]]; |
| | | } |
| | | |
| | | return NO; |
| | | } |
| | | else if ([text isEqualToString:@"@"]) { |
| | | if ([self.delegate respondsToSelector:@selector(didInputAtInLocation:)]) { |
| | | if ([self.delegate didInputAtInLocation:range.location]) { |
| | | [self _willShowInputTextViewToHeight:[self _getTextViewContentH:self.inputTextView]]; |
| | | return NO; |
| | | } |
| | | } |
| | | } |
| | | else if ([text length] == 0) { |
| | | //delete one character |
| | | if (range.length == 1 && [self.delegate respondsToSelector:@selector(didDeleteCharacterFromLocation:)]) { |
| | | return ![self.delegate didDeleteCharacterFromLocation:range.location]; |
| | | } |
| | | } |
| | | return YES; |
| | | } |
| | | |
| | | - (void)textViewDidChange:(UITextView *)textView |
| | | { |
| | | [self _willShowInputTextViewToHeight:[self _getTextViewContentH:textView]]; |
| | | } |
| | | |
| | | #pragma mark - DXFaceDelegate |
| | | |
| | | - (void)selectedFacialView:(NSString *)str isDelete:(BOOL)isDelete |
| | | { |
| | | NSString *chatText = self.inputTextView.text; |
| | | |
| | | NSMutableAttributedString *attr = [[NSMutableAttributedString alloc] initWithAttributedString:self.inputTextView.attributedText]; |
| | | |
| | | if (!isDelete && str.length > 0) { |
| | | if (self.version >= 7.0) { |
| | | NSRange range = [self.inputTextView selectedRange]; |
| | | [attr insertAttributedString:[[EaseEmotionEscape sharedInstance] attStringFromTextForInputView:str textFont:self.inputTextView.font] atIndex:range.location]; |
| | | self.inputTextView.attributedText = attr; |
| | | } else { |
| | | self.inputTextView.text = @""; |
| | | self.inputTextView.text = [NSString stringWithFormat:@"%@%@",chatText,str]; |
| | | } |
| | | } |
| | | else { |
| | | if (self.version >= 7.0) { |
| | | if (chatText.length > 0) { |
| | | NSInteger length = 1; |
| | | if (chatText.length >= 2) { |
| | | NSString *subStr = [chatText substringFromIndex:chatText.length-2]; |
| | | if ([EaseEmoji stringContainsEmoji:subStr]) { |
| | | length = 2; |
| | | } |
| | | } |
| | | self.inputTextView.attributedText = [self backspaceText:attr length:length]; |
| | | } |
| | | } else { |
| | | if (chatText.length >= 2) |
| | | { |
| | | NSString *subStr = [chatText substringFromIndex:chatText.length-2]; |
| | | if ([(EaseFaceView *)self.faceView stringIsFace:subStr]) { |
| | | self.inputTextView.text = [chatText substringToIndex:chatText.length-2]; |
| | | [self textViewDidChange:self.inputTextView]; |
| | | return; |
| | | } |
| | | } |
| | | |
| | | if (chatText.length > 0) { |
| | | self.inputTextView.text = [chatText substringToIndex:chatText.length-1]; |
| | | } |
| | | } |
| | | } |
| | | |
| | | [self textViewDidChange:self.inputTextView]; |
| | | } |
| | | |
| | | /*! |
| | | @method |
| | | @brief 删除文本光标前长度为length的字符串 |
| | | @discussion |
| | | @param attr 待修改的富文本 |
| | | @param length 字符串长度 |
| | | @result 修改后的富文本 |
| | | */ |
| | | -(NSMutableAttributedString*)backspaceText:(NSMutableAttributedString*) attr length:(NSInteger)length |
| | | { |
| | | NSRange range = [self.inputTextView selectedRange]; |
| | | if (range.location == 0) { |
| | | return attr; |
| | | } |
| | | [attr deleteCharactersInRange:NSMakeRange(range.location - length, length)]; |
| | | return attr; |
| | | } |
| | | |
| | | - (void)sendFace |
| | | { |
| | | NSString *chatText = self.inputTextView.text; |
| | | if (chatText.length > 0) { |
| | | if ([self.delegate respondsToSelector:@selector(didSendText:)]) { |
| | | |
| | | if (![_inputTextView.text isEqualToString:@""]) { |
| | | |
| | | //转义回来 |
| | | NSMutableString *attStr = [[NSMutableString alloc] initWithString:self.inputTextView.attributedText.string]; |
| | | [_inputTextView.attributedText enumerateAttribute:NSAttachmentAttributeName |
| | | inRange:NSMakeRange(0, self.inputTextView.attributedText.length) |
| | | options:NSAttributedStringEnumerationReverse |
| | | usingBlock:^(id value, NSRange range, BOOL *stop) |
| | | { |
| | | if (value) { |
| | | EMTextAttachment* attachment = (EMTextAttachment*)value; |
| | | NSString *str = [NSString stringWithFormat:@"%@",attachment.imageName]; |
| | | [attStr replaceCharactersInRange:range withString:str]; |
| | | } |
| | | }]; |
| | | [self.delegate didSendText:attStr]; |
| | | self.inputTextView.text = @""; |
| | | [self _willShowInputTextViewToHeight:[self _getTextViewContentH:self.inputTextView]];; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | - (void)sendFaceWithEmotion:(EaseEmotion *)emotion |
| | | { |
| | | if (emotion) { |
| | | if ([self.delegate respondsToSelector:@selector(didSendText:withExt:)]) { |
| | | [self.delegate didSendText:emotion.emotionTitle withExt:@{EASEUI_EMOTION_DEFAULT_EXT:emotion}]; |
| | | [self _willShowInputTextViewToHeight:[self _getTextViewContentH:self.inputTextView]];; |
| | | } |
| | | } |
| | | } |
| | | |
| | | #pragma mark - UIKeyboardNotification |
| | | |
| | | - (void)chatKeyboardWillChangeFrame:(NSNotification *)notification |
| | | { |
| | | NSDictionary *userInfo = notification.userInfo; |
| | | CGRect endFrame = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; |
| | | CGRect beginFrame = [userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue]; |
| | | CGFloat duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; |
| | | UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]; |
| | | |
| | | void(^animations)() = ^{ |
| | | [self _willShowKeyboardFromFrame:beginFrame toFrame:endFrame]; |
| | | }; |
| | | |
| | | [UIView animateWithDuration:duration delay:0.0f options:(curve << 16 | UIViewAnimationOptionBeginFromCurrentState) animations:animations completion:nil]; |
| | | } |
| | | |
| | | #pragma mark - action |
| | | |
| | | - (void)styleButtonAction:(id)sender |
| | | { |
| | | UIButton *button = (UIButton *)sender; |
| | | button.selected = !button.selected; |
| | | if (button.selected) { |
| | | for (EaseChatToolbarItem *item in self.rightItems) { |
| | | item.button.selected = NO; |
| | | } |
| | | |
| | | for (EaseChatToolbarItem *item in self.leftItems) { |
| | | if (item.button != button) { |
| | | item.button.selected = NO; |
| | | } |
| | | } |
| | | |
| | | [self _willShowBottomView:nil]; |
| | | |
| | | self.inputTextView.text = @""; |
| | | [self textViewDidChange:self.inputTextView]; |
| | | [self.inputTextView resignFirstResponder]; |
| | | } |
| | | else{ |
| | | [self.inputTextView becomeFirstResponder]; |
| | | } |
| | | |
| | | [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ |
| | | self.recordButton.hidden = !button.selected; |
| | | self.inputTextView.hidden = button.selected; |
| | | } completion:nil]; |
| | | } |
| | | |
| | | - (void)faceButtonAction:(id)sender |
| | | { |
| | | UIButton *button = (UIButton *)sender; |
| | | button.selected = !button.selected; |
| | | |
| | | EaseChatToolbarItem *faceItem = nil; |
| | | for (EaseChatToolbarItem *item in self.rightItems) { |
| | | if (item.button == button){ |
| | | faceItem = item; |
| | | continue; |
| | | } |
| | | |
| | | item.button.selected = NO; |
| | | } |
| | | |
| | | for (EaseChatToolbarItem *item in self.leftItems) { |
| | | item.button.selected = NO; |
| | | } |
| | | |
| | | if (button.selected) { |
| | | [self.inputTextView resignFirstResponder]; |
| | | |
| | | [self _willShowBottomView:faceItem.button2View]; |
| | | [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ |
| | | self.recordButton.hidden = button.selected; |
| | | self.inputTextView.hidden = !button.selected; |
| | | } completion:^(BOOL finished) { |
| | | |
| | | }]; |
| | | } else { |
| | | [self.inputTextView becomeFirstResponder]; |
| | | } |
| | | } |
| | | |
| | | - (void)moreButtonAction:(id)sender |
| | | { |
| | | UIButton *button = (UIButton *)sender; |
| | | button.selected = !button.selected; |
| | | |
| | | EaseChatToolbarItem *moreItem = nil; |
| | | for (EaseChatToolbarItem *item in self.rightItems) { |
| | | if (item.button == button){ |
| | | moreItem = item; |
| | | continue; |
| | | } |
| | | |
| | | item.button.selected = NO; |
| | | } |
| | | |
| | | for (EaseChatToolbarItem *item in self.leftItems) { |
| | | item.button.selected = NO; |
| | | } |
| | | |
| | | if (button.selected) { |
| | | [self.inputTextView resignFirstResponder]; |
| | | |
| | | [self _willShowBottomView:moreItem.button2View]; |
| | | [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ |
| | | self.recordButton.hidden = button.selected; |
| | | self.inputTextView.hidden = !button.selected; |
| | | } completion:nil]; |
| | | } |
| | | else |
| | | { |
| | | [self.inputTextView becomeFirstResponder]; |
| | | } |
| | | } |
| | | |
| | | - (void)recordButtonTouchDown |
| | | { |
| | | if (_delegate && [_delegate respondsToSelector:@selector(didStartRecordingVoiceAction:)]) { |
| | | [_delegate didStartRecordingVoiceAction:self.recordView]; |
| | | } |
| | | } |
| | | |
| | | - (void)recordButtonTouchUpOutside |
| | | { |
| | | if (_delegate && [_delegate respondsToSelector:@selector(didCancelRecordingVoiceAction:)]) |
| | | { |
| | | [_delegate didCancelRecordingVoiceAction:self.recordView]; |
| | | } |
| | | } |
| | | |
| | | - (void)recordButtonTouchUpInside |
| | | { |
| | | self.recordButton.enabled = NO; |
| | | if ([self.delegate respondsToSelector:@selector(didFinishRecoingVoiceAction:)]) |
| | | { |
| | | [self.delegate didFinishRecoingVoiceAction:self.recordView]; |
| | | } |
| | | self.recordButton.enabled = YES; |
| | | } |
| | | |
| | | - (void)recordDragOutside |
| | | { |
| | | if ([self.delegate respondsToSelector:@selector(didDragOutsideAction:)]) |
| | | { |
| | | [self.delegate didDragOutsideAction:self.recordView]; |
| | | } |
| | | } |
| | | |
| | | - (void)recordDragInside |
| | | { |
| | | if ([self.delegate respondsToSelector:@selector(didDragInsideAction:)]) |
| | | { |
| | | [self.delegate didDragInsideAction:self.recordView]; |
| | | } |
| | | } |
| | | |
| | | #pragma mark - public |
| | | |
| | | + (CGFloat)defaultHeight |
| | | { |
| | | return 5 * 2 + 36; |
| | | } |
| | | |
| | | - (BOOL)endEditing:(BOOL)force |
| | | { |
| | | BOOL result = [super endEditing:force]; |
| | | |
| | | for (EaseChatToolbarItem *item in self.rightItems) { |
| | | item.button.selected = NO; |
| | | } |
| | | [self _willShowBottomView:nil]; |
| | | |
| | | return result; |
| | | } |
| | | |
| | | - (void)cancelTouchRecord |
| | | { |
| | | if ([_recordView isKindOfClass:[EaseRecordView class]]) { |
| | | [(EaseRecordView *)_recordView recordButtonTouchUpInside]; |
| | | [_recordView removeFromSuperview]; |
| | | } |
| | | } |
| | | |
| | | - (void)willShowBottomView:(UIView *)bottomView |
| | | { |
| | | [self _willShowBottomView:bottomView]; |
| | | } |
| | | |
| | | @end |