chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// TLTalkButton.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/7/11.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface TLTalkButton : UIView
|
||||
|
||||
@property (nonatomic, strong) NSString *normalTitle;
|
||||
@property (nonatomic, strong) NSString *cancelTitle;
|
||||
@property (nonatomic, strong) NSString *highlightTitle;
|
||||
|
||||
@property (nonatomic, strong) UIColor *highlightColor;
|
||||
|
||||
@property (nonatomic, strong) UILabel *titleLabel;
|
||||
|
||||
- (void)setTouchBeginAction:(void (^)())touchBegin
|
||||
willTouchCancelAction:(void (^)(BOOL cancel))willTouchCancel
|
||||
touchEndAction:(void (^)())touchEnd
|
||||
touchCancelAction:(void (^)())touchCancel;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,115 @@
|
||||
|
||||
//
|
||||
// TLTalkButton.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/7/11.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLTalkButton.h"
|
||||
#import "UIImage+Color.h"
|
||||
|
||||
@interface TLTalkButton ()
|
||||
|
||||
@property (nonatomic, strong) void (^touchBegin)();
|
||||
@property (nonatomic, strong) void (^touchMove)(BOOL cancel);
|
||||
@property (nonatomic, strong) void (^touchCancel)();
|
||||
@property (nonatomic, strong) void (^touchEnd)();
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLTalkButton
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self setNormalTitle:@"按住 说话"];
|
||||
[self setHighlightTitle:@"松开 结束"];
|
||||
[self setCancelTitle:@"送开 取消"];
|
||||
[self setHighlightColor:[UIColor colorWithWhite:0.0 alpha:0.1]];
|
||||
[self.layer setMasksToBounds:YES];
|
||||
[self.layer setCornerRadius:4.0f];
|
||||
[self.layer setBorderWidth:BORDER_WIDTH_1PX];
|
||||
[self.layer setBorderColor:[UIColor colorWithWhite:0.0 alpha:0.3].CGColor];
|
||||
|
||||
[self addSubview:self.titleLabel];
|
||||
[self p_addMasonry];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - # Public Methods
|
||||
- (void)setTouchBeginAction:(void (^)())touchBegin willTouchCancelAction:(void (^)(BOOL))willTouchCancel touchEndAction:(void (^)())touchEnd touchCancelAction:(void (^)())touchCancel
|
||||
{
|
||||
self.touchBegin = touchBegin;
|
||||
self.touchMove = willTouchCancel;
|
||||
self.touchCancel= touchCancel;
|
||||
self.touchEnd = touchEnd;
|
||||
}
|
||||
|
||||
#pragma mark - # Event Response
|
||||
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
[self setBackgroundColor:self.highlightColor];
|
||||
[self.titleLabel setText:self.highlightTitle];
|
||||
if (self.touchBegin) {
|
||||
self.touchBegin();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
if (self.touchMove) {
|
||||
CGPoint curPoint = [[touches anyObject] locationInView:self];
|
||||
BOOL moveIn = curPoint.x >= 0 && curPoint.x <= self.width && curPoint.y >= 0 && curPoint.y <= self.height;
|
||||
[self.titleLabel setText:(moveIn ? self.highlightTitle : self.cancelTitle)];
|
||||
self.touchMove(!moveIn);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
[self setBackgroundColor:[UIColor clearColor]];
|
||||
[self.titleLabel setText:self.normalTitle];
|
||||
CGPoint curPoint = [[touches anyObject] locationInView:self];
|
||||
BOOL moveIn = curPoint.x >= 0 && curPoint.x <= self.width && curPoint.y >= 0 && curPoint.y <= self.height;
|
||||
if (moveIn && self.touchEnd) {
|
||||
self.touchEnd();
|
||||
}
|
||||
else if (!moveIn && self.touchCancel) {
|
||||
self.touchCancel();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
[self setBackgroundColor:[UIColor clearColor]];
|
||||
[self.titleLabel setText:self.normalTitle];
|
||||
if (self.touchCancel) {
|
||||
self.touchCancel();
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - # Private Methods
|
||||
- (void)p_addMasonry
|
||||
{
|
||||
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.mas_equalTo(self);
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - # Getter
|
||||
- (UILabel *)titleLabel
|
||||
{
|
||||
if (_titleLabel == nil) {
|
||||
_titleLabel = [[UILabel alloc] init];
|
||||
[_titleLabel setFont:[UIFont boldSystemFontOfSize:16.0f]];
|
||||
[_titleLabel setTextColor:[UIColor colorWithRed:0.3 green:0.3 blue:0.3 alpha:1.0]];
|
||||
[_titleLabel setTextAlignment:NSTextAlignmentCenter];
|
||||
[_titleLabel setText:self.normalTitle];
|
||||
}
|
||||
return _titleLabel;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// TLChatBar.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/15.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TLChatBarDelegate.h"
|
||||
|
||||
@interface TLChatBar : UIView
|
||||
|
||||
@property (nonatomic, assign) id<TLChatBarDelegate> delegate;
|
||||
|
||||
@property (nonatomic, assign) TLChatBarStatus status;
|
||||
|
||||
@property (nonatomic, strong, readonly) NSString *curText;
|
||||
|
||||
/// 是否激活状态(浏览个性表情时应该设置为NO)
|
||||
@property (nonatomic, assign) BOOL activity;
|
||||
|
||||
/**
|
||||
* 添加EmojiB表情String
|
||||
*/
|
||||
- (void)addEmojiString:(NSString *)emojiString;
|
||||
|
||||
/**
|
||||
* 发送文字消息
|
||||
*/
|
||||
- (void)sendCurrentText;
|
||||
|
||||
/**
|
||||
* 删除最后一个字符
|
||||
*/
|
||||
- (void)deleteLastCharacter;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,525 @@
|
||||
//
|
||||
// TLChatBar.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/15.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLChatBar.h"
|
||||
#import "TLChatMacros.h"
|
||||
#import "TLTalkButton.h"
|
||||
|
||||
@interface TLChatBar () <UITextViewDelegate>
|
||||
{
|
||||
UIImage *kVoiceImage;
|
||||
UIImage *kVoiceImageHL;
|
||||
UIImage *kEmojiImage;
|
||||
UIImage *kEmojiImageHL;
|
||||
UIImage *kMoreImage;
|
||||
UIImage *kMoreImageHL;
|
||||
UIImage *kKeyboardImage;
|
||||
UIImage *kKeyboardImageHL;
|
||||
}
|
||||
|
||||
@property (nonatomic, strong) UIButton *modeButton;
|
||||
|
||||
@property (nonatomic, strong) UIButton *voiceButton;
|
||||
|
||||
@property (nonatomic, strong) UITextView *textView;
|
||||
|
||||
@property (nonatomic, strong) TLTalkButton *talkButton;
|
||||
|
||||
@property (nonatomic, strong) UIButton *emojiButton;
|
||||
|
||||
@property (nonatomic, strong) UIButton *moreButton;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLChatBar
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
[self setBackgroundColor:[UIColor colorGrayForChatBar]];
|
||||
[self p_initImage];
|
||||
|
||||
[self addSubview:self.modeButton];
|
||||
[self addSubview:self.voiceButton];
|
||||
[self addSubview:self.textView];
|
||||
[self addSubview:self.talkButton];
|
||||
[self addSubview:self.emojiButton];
|
||||
[self addSubview:self.moreButton];
|
||||
|
||||
[self p_addMasonry];
|
||||
|
||||
self.status = TLChatBarStatusInit;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
#ifdef DEBUG_MEMERY
|
||||
NSLog(@"dealloc ChatBar");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
|
||||
#pragma mark - Public Methods
|
||||
- (void)sendCurrentText
|
||||
{
|
||||
if (self.textView.text.length > 0) { // send Text
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(chatBar:sendText:)]) {
|
||||
[_delegate chatBar:self sendText:self.textView.text];
|
||||
}
|
||||
}
|
||||
[self.textView setText:@""];
|
||||
[self p_reloadTextViewWithAnimation:YES];
|
||||
}
|
||||
|
||||
- (void)addEmojiString:(NSString *)emojiString
|
||||
{
|
||||
NSString *str = [NSString stringWithFormat:@"%@%@", self.textView.text, emojiString];
|
||||
[self.textView setText:str];
|
||||
[self p_reloadTextViewWithAnimation:YES];
|
||||
}
|
||||
|
||||
- (void)deleteLastCharacter
|
||||
{
|
||||
if([self textView:self.textView shouldChangeTextInRange:NSMakeRange(self.textView.text.length - 1, 1) replacementText:@""]){
|
||||
[self.textView deleteBackward];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setActivity:(BOOL)activity
|
||||
{
|
||||
_activity = activity;
|
||||
if (activity) {
|
||||
[self.textView setTextColor:[UIColor blackColor]];
|
||||
}
|
||||
else {
|
||||
[self.textView setTextColor:[UIColor grayColor]];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isFirstResponder
|
||||
{
|
||||
if (self.status == TLChatBarStatusEmoji || self.status == TLChatBarStatusKeyboard || self.status == TLChatBarStatusMore) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)resignFirstResponder
|
||||
{
|
||||
[self.moreButton setImage:kMoreImage imageHL:kMoreImageHL];
|
||||
[self.emojiButton setImage:kEmojiImage imageHL:kEmojiImageHL];
|
||||
if (self.status == TLChatBarStatusKeyboard) {
|
||||
[self.textView resignFirstResponder];
|
||||
self.status = TLChatBarStatusInit;
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(chatBar:changeStatusFrom:to:)]) {
|
||||
[self.delegate chatBar:self changeStatusFrom:self.status to:TLChatBarStatusInit];
|
||||
}
|
||||
}
|
||||
|
||||
return [super resignFirstResponder];
|
||||
}
|
||||
|
||||
#pragma mark - Delegate -
|
||||
//MARK: UITextViewDelegate
|
||||
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
|
||||
{
|
||||
[self setActivity:YES];
|
||||
if (self.status != TLChatBarStatusKeyboard) {
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(chatBar:changeStatusFrom:to:)]) {
|
||||
[self.delegate chatBar:self changeStatusFrom:self.status to:TLChatBarStatusKeyboard];
|
||||
}
|
||||
if (self.status == TLChatBarStatusEmoji) {
|
||||
[self.emojiButton setImage:kEmojiImage imageHL:kEmojiImageHL];
|
||||
}
|
||||
else if (self.status == TLChatBarStatusMore) {
|
||||
[self.moreButton setImage:kMoreImage imageHL:kMoreImageHL];
|
||||
}
|
||||
self.status = TLChatBarStatusKeyboard;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
|
||||
{
|
||||
if ([text isEqualToString:@"\n"]){
|
||||
[self sendCurrentText];
|
||||
return NO;
|
||||
}
|
||||
else if (textView.text.length > 0 && [text isEqualToString:@""]) { // delete
|
||||
if ([textView.text characterAtIndex:range.location] == ']') {
|
||||
NSUInteger location = range.location;
|
||||
NSUInteger length = range.length;
|
||||
while (location != 0) {
|
||||
location --;
|
||||
length ++ ;
|
||||
char c = [textView.text characterAtIndex:location];
|
||||
if (c == '[') {
|
||||
textView.text = [textView.text stringByReplacingCharactersInRange:NSMakeRange(location, length) withString:@""];
|
||||
[self p_reloadTextViewWithAnimation:YES];
|
||||
return NO;
|
||||
}
|
||||
else if (c == ']') {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)textViewDidEndEditing:(UITextView *)textView
|
||||
{
|
||||
[self p_reloadTextViewWithAnimation:YES];
|
||||
}
|
||||
|
||||
- (void)textViewDidChange:(UITextView *)textView
|
||||
{
|
||||
[self p_reloadTextViewWithAnimation:YES];
|
||||
}
|
||||
|
||||
#pragma mark - Event Response
|
||||
- (void)modeButtonDown
|
||||
{
|
||||
if (self.status == TLChatBarStatusEmoji) {
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(chatBar:changeStatusFrom:to:)]) {
|
||||
[self.delegate chatBar:self changeStatusFrom:self.status to:TLChatBarStatusInit];
|
||||
}
|
||||
[self.emojiButton setImage:kEmojiImage imageHL:kEmojiImageHL];
|
||||
self.status = TLChatBarStatusInit;
|
||||
|
||||
}
|
||||
else if (self.status == TLChatBarStatusMore) {
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(chatBar:changeStatusFrom:to:)]) {
|
||||
[self.delegate chatBar:self changeStatusFrom:self.status to:TLChatBarStatusInit];
|
||||
}
|
||||
[self.moreButton setImage:kMoreImage imageHL:kMoreImageHL];
|
||||
self.status = TLChatBarStatusInit;
|
||||
}
|
||||
}
|
||||
|
||||
static NSString *textRec = @"";
|
||||
- (void)voiceButtonDown
|
||||
{
|
||||
[self.textView resignFirstResponder];
|
||||
|
||||
// 开始文字输入
|
||||
if (self.status == TLChatBarStatusVoice) {
|
||||
if (textRec.length > 0) {
|
||||
[self.textView setText:textRec];
|
||||
textRec = @"";
|
||||
[self p_reloadTextViewWithAnimation:YES];
|
||||
}
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(chatBar:changeStatusFrom:to:)]) {
|
||||
[self.delegate chatBar:self changeStatusFrom:self.status to:TLChatBarStatusKeyboard];
|
||||
}
|
||||
[self.voiceButton setImage:kVoiceImage imageHL:kVoiceImageHL];
|
||||
[self.textView becomeFirstResponder];
|
||||
[self.textView setHidden:NO];
|
||||
[self.talkButton setHidden:YES];
|
||||
self.status = TLChatBarStatusKeyboard;
|
||||
}
|
||||
else { // 开始语音
|
||||
if (self.textView.text.length > 0) {
|
||||
textRec = self.textView.text;
|
||||
self.textView.text = @"";
|
||||
[self p_reloadTextViewWithAnimation:YES];
|
||||
}
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(chatBar:changeStatusFrom:to:)]) {
|
||||
[self.delegate chatBar:self changeStatusFrom:self.status to:TLChatBarStatusVoice];
|
||||
}
|
||||
if (self.status == TLChatBarStatusKeyboard) {
|
||||
[self.textView resignFirstResponder];
|
||||
}
|
||||
else if (self.status == TLChatBarStatusEmoji) {
|
||||
[self.emojiButton setImage:kEmojiImage imageHL:kEmojiImageHL];
|
||||
}
|
||||
else if (self.status == TLChatBarStatusMore) {
|
||||
[self.moreButton setImage:kMoreImage imageHL:kMoreImageHL];
|
||||
}
|
||||
[self.talkButton setHidden:NO];
|
||||
[self.textView setHidden:YES];
|
||||
[self.voiceButton setImage:kKeyboardImage imageHL:kKeyboardImageHL];
|
||||
self.status = TLChatBarStatusVoice;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)emojiButtonDown
|
||||
{
|
||||
// 开始文字输入
|
||||
if (self.status == TLChatBarStatusEmoji) {
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(chatBar:changeStatusFrom:to:)]) {
|
||||
[self.delegate chatBar:self changeStatusFrom:self.status to:TLChatBarStatusKeyboard];
|
||||
}
|
||||
[self.emojiButton setImage:kEmojiImage imageHL:kEmojiImageHL];
|
||||
[self.textView becomeFirstResponder];
|
||||
self.status = TLChatBarStatusKeyboard;
|
||||
}
|
||||
else { // 打开表情键盘
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(chatBar:changeStatusFrom:to:)]) {
|
||||
[self.delegate chatBar:self changeStatusFrom:self.status to:TLChatBarStatusEmoji];
|
||||
}
|
||||
if (self.status == TLChatBarStatusVoice) {
|
||||
[self.voiceButton setImage:kVoiceImage imageHL:kVoiceImageHL];
|
||||
[self.talkButton setHidden:YES];
|
||||
[self.textView setHidden:NO];
|
||||
}
|
||||
else if (self.status == TLChatBarStatusMore) {
|
||||
[self.moreButton setImage:kMoreImage imageHL:kMoreImageHL];
|
||||
}
|
||||
[self.emojiButton setImage:kKeyboardImage imageHL:kKeyboardImageHL];
|
||||
[self.textView resignFirstResponder];
|
||||
self.status = TLChatBarStatusEmoji;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)moreButtonDown
|
||||
{
|
||||
// 开始文字输入
|
||||
if (self.status == TLChatBarStatusMore) {
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(chatBar:changeStatusFrom:to:)]) {
|
||||
[self.delegate chatBar:self changeStatusFrom:self.status to:TLChatBarStatusKeyboard];
|
||||
}
|
||||
[self.moreButton setImage:kMoreImage imageHL:kMoreImageHL];
|
||||
[self.textView becomeFirstResponder];
|
||||
self.status = TLChatBarStatusKeyboard;
|
||||
}
|
||||
else { // 打开更多键盘
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(chatBar:changeStatusFrom:to:)]) {
|
||||
[self.delegate chatBar:self changeStatusFrom:self.status to:TLChatBarStatusMore];
|
||||
}
|
||||
if (self.status == TLChatBarStatusVoice) {
|
||||
[self.voiceButton setImage:kVoiceImage imageHL:kVoiceImageHL];
|
||||
[self.talkButton setHidden:YES];
|
||||
[self.textView setHidden:NO];
|
||||
}
|
||||
else if (self.status == TLChatBarStatusEmoji) {
|
||||
[self.emojiButton setImage:kEmojiImage imageHL:kEmojiImageHL];
|
||||
}
|
||||
[self.moreButton setImage:kKeyboardImage imageHL:kKeyboardImageHL];
|
||||
[self.textView resignFirstResponder];
|
||||
self.status = TLChatBarStatusMore;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Private Methods
|
||||
- (void)p_reloadTextViewWithAnimation:(BOOL)animation
|
||||
{
|
||||
CGFloat textHeight = [self.textView sizeThatFits:CGSizeMake(self.textView.width, MAXFLOAT)].height;
|
||||
CGFloat height = textHeight > HEIGHT_CHATBAR_TEXTVIEW ? textHeight : HEIGHT_CHATBAR_TEXTVIEW;
|
||||
height = (textHeight <= HEIGHT_MAX_CHATBAR_TEXTVIEW ? textHeight : HEIGHT_MAX_CHATBAR_TEXTVIEW);
|
||||
[self.textView setScrollEnabled:textHeight > height];
|
||||
if (height != self.textView.height) {
|
||||
if (animation) {
|
||||
[UIView animateWithDuration:0.2 animations:^{
|
||||
[self.textView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.height.mas_equalTo(height);
|
||||
}];
|
||||
if (self.superview) {
|
||||
[self.superview layoutIfNeeded];
|
||||
}
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(chatBar:didChangeTextViewHeight:)]) {
|
||||
[self.delegate chatBar:self didChangeTextViewHeight:self.textView.height];
|
||||
}
|
||||
} completion:^(BOOL finished) {
|
||||
if (textHeight > height) {
|
||||
[self.textView setContentOffset:CGPointMake(0, textHeight - height) animated:YES];
|
||||
}
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(chatBar:didChangeTextViewHeight:)]) {
|
||||
[self.delegate chatBar:self didChangeTextViewHeight:height];
|
||||
}
|
||||
}];
|
||||
}
|
||||
else {
|
||||
[self.textView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.height.mas_equalTo(height);
|
||||
}];
|
||||
if (self.superview) {
|
||||
[self.superview layoutIfNeeded];
|
||||
}
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(chatBar:didChangeTextViewHeight:)]) {
|
||||
[self.delegate chatBar:self didChangeTextViewHeight:height];
|
||||
}
|
||||
if (textHeight > height) {
|
||||
[self.textView setContentOffset:CGPointMake(0, textHeight - height) animated:YES];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (textHeight > height) {
|
||||
if (animation) {
|
||||
CGFloat offsetY = self.textView.contentSize.height - self.textView.height;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.textView setContentOffset:CGPointMake(0, offsetY) animated:YES];
|
||||
});
|
||||
}
|
||||
else {
|
||||
[self.textView setContentOffset:CGPointMake(0, self.textView.contentSize.height - self.textView.height) animated:NO];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)p_addMasonry
|
||||
{
|
||||
[self.modeButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.mas_equalTo(self);
|
||||
make.bottom.mas_equalTo(self).mas_offset(-4);
|
||||
make.width.mas_equalTo(0);
|
||||
}];
|
||||
|
||||
[self.voiceButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.bottom.mas_equalTo(self).mas_offset(-7);
|
||||
make.left.mas_equalTo(self.modeButton.mas_right).mas_offset(1);
|
||||
make.width.mas_equalTo(38);
|
||||
}];
|
||||
|
||||
[self.textView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(self).mas_offset(7);
|
||||
make.bottom.mas_equalTo(self).mas_offset(-7);
|
||||
make.left.mas_equalTo(self.voiceButton.mas_right).mas_offset(4);
|
||||
make.right.mas_equalTo(self.emojiButton.mas_left).mas_offset(-4);
|
||||
make.height.mas_equalTo(HEIGHT_CHATBAR_TEXTVIEW);
|
||||
}];
|
||||
|
||||
[self.talkButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.center.mas_equalTo(self.textView);
|
||||
make.size.mas_equalTo(self.textView);
|
||||
}];
|
||||
|
||||
[self.moreButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.and.width.mas_equalTo(self.voiceButton);
|
||||
make.right.mas_equalTo(self).mas_offset(-1);
|
||||
}];
|
||||
|
||||
[self.emojiButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.and.width.mas_equalTo(self.voiceButton);
|
||||
make.right.mas_equalTo(self.moreButton.mas_left);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)p_initImage
|
||||
{
|
||||
kVoiceImage = [UIImage imageNamed:@"chat_toolbar_voice"];
|
||||
kVoiceImageHL = [UIImage imageNamed:@"chat_toolbar_voice_HL"];
|
||||
kEmojiImage = [UIImage imageNamed:@"chat_toolbar_emotion"];
|
||||
kEmojiImageHL = [UIImage imageNamed:@"chat_toolbar_emotion_HL"];
|
||||
kMoreImage = [UIImage imageNamed:@"chat_toolbar_more"];
|
||||
kMoreImageHL = [UIImage imageNamed:@"chat_toolbar_more_HL"];
|
||||
kKeyboardImage = [UIImage imageNamed:@"chat_toolbar_keyboard"];
|
||||
kKeyboardImageHL = [UIImage imageNamed:@"chat_toolbar_keyboard_HL"];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)rect
|
||||
{
|
||||
[super drawRect:rect];
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
CGContextSetLineWidth(context, 0.5);
|
||||
CGContextSetStrokeColorWithColor(context, [UIColor colorGrayLine].CGColor);
|
||||
CGContextBeginPath(context);
|
||||
CGContextMoveToPoint(context, 0, 0);
|
||||
CGContextAddLineToPoint(context, SCREEN_WIDTH, 0);
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
#pragma mark - Getter
|
||||
- (UIButton *)modeButton
|
||||
{
|
||||
if (_modeButton == nil) {
|
||||
_modeButton = [[UIButton alloc] init];
|
||||
[_modeButton setImage:[UIImage imageNamed:@"chat_toolbar_texttolist"] imageHL:[UIImage imageNamed:@"chat_toolbar_texttolist_HL"]];
|
||||
[_modeButton addTarget:self action:@selector(modeButtonDown) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _modeButton;
|
||||
}
|
||||
|
||||
- (UIButton *)voiceButton
|
||||
{
|
||||
if (_voiceButton == nil) {
|
||||
_voiceButton = [[UIButton alloc] init];
|
||||
[_voiceButton setImage:kVoiceImage imageHL:kVoiceImageHL];
|
||||
[_voiceButton addTarget:self action:@selector(voiceButtonDown) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _voiceButton;
|
||||
}
|
||||
|
||||
- (UITextView *)textView
|
||||
{
|
||||
if (_textView == nil) {
|
||||
_textView = [[UITextView alloc] init];
|
||||
[_textView setFont:[UIFont systemFontOfSize:16.0f]];
|
||||
[_textView setReturnKeyType:UIReturnKeySend];
|
||||
[_textView.layer setMasksToBounds:YES];
|
||||
[_textView.layer setBorderWidth:BORDER_WIDTH_1PX];
|
||||
[_textView.layer setBorderColor:[UIColor colorWithWhite:0.0 alpha:0.3].CGColor];
|
||||
[_textView.layer setCornerRadius:4.0f];
|
||||
[_textView setDelegate:self];
|
||||
[_textView setScrollsToTop:NO];
|
||||
}
|
||||
return _textView;
|
||||
}
|
||||
|
||||
- (TLTalkButton *)talkButton
|
||||
{
|
||||
if (_talkButton == nil) {
|
||||
_talkButton = [[TLTalkButton alloc] init];
|
||||
[_talkButton setHidden:YES];
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[_talkButton setTouchBeginAction:^{
|
||||
if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(chatBarStartRecording:)]) {
|
||||
[weakSelf.delegate chatBarStartRecording:weakSelf];
|
||||
}
|
||||
} willTouchCancelAction:^(BOOL cancel) {
|
||||
if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(chatBarWillCancelRecording:cancel:)]) {
|
||||
[weakSelf.delegate chatBarWillCancelRecording:weakSelf cancel:cancel];
|
||||
}
|
||||
} touchEndAction:^{
|
||||
if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(chatBarFinishedRecoding:)]) {
|
||||
[weakSelf.delegate chatBarFinishedRecoding:weakSelf];
|
||||
}
|
||||
} touchCancelAction:^{
|
||||
if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(chatBarDidCancelRecording:)]) {
|
||||
[weakSelf.delegate chatBarDidCancelRecording:weakSelf];
|
||||
}
|
||||
}];
|
||||
}
|
||||
return _talkButton;
|
||||
}
|
||||
|
||||
- (UIButton *)emojiButton
|
||||
{
|
||||
if (_emojiButton == nil) {
|
||||
_emojiButton = [[UIButton alloc] init];
|
||||
[_emojiButton setImage:kEmojiImage imageHL:kEmojiImageHL];
|
||||
[_emojiButton addTarget:self action:@selector(emojiButtonDown) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _emojiButton;
|
||||
}
|
||||
|
||||
- (UIButton *)moreButton
|
||||
{
|
||||
if (_moreButton == nil) {
|
||||
_moreButton = [[UIButton alloc] init];
|
||||
[_moreButton setImage:kMoreImage imageHL:kMoreImageHL];
|
||||
[_moreButton addTarget:self action:@selector(moreButtonDown) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _moreButton;
|
||||
}
|
||||
|
||||
- (NSString *)curText
|
||||
{
|
||||
return self.textView.text;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// TLChatBarDelegate.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/1.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "TLChatMacros.h"
|
||||
|
||||
@class TLChatBar;
|
||||
@protocol TLChatBarDelegate <NSObject>
|
||||
|
||||
/**
|
||||
* chatBar状态改变
|
||||
*/
|
||||
- (void)chatBar:(TLChatBar *)chatBar changeStatusFrom:(TLChatBarStatus)fromStatus to:(TLChatBarStatus)toStatus;
|
||||
|
||||
/**
|
||||
* 输入框高度改变
|
||||
*/
|
||||
- (void)chatBar:(TLChatBar *)chatBar didChangeTextViewHeight:(CGFloat)height;
|
||||
|
||||
/**
|
||||
* 发送文字
|
||||
*/
|
||||
- (void)chatBar:(TLChatBar *)chatBar sendText:(NSString *)text;
|
||||
|
||||
|
||||
// 录音控制
|
||||
- (void)chatBarStartRecording:(TLChatBar *)chatBar;
|
||||
|
||||
- (void)chatBarWillCancelRecording:(TLChatBar *)chatBar cancel:(BOOL)cancel;
|
||||
|
||||
- (void)chatBarDidCancelRecording:(TLChatBar *)chatBar;
|
||||
|
||||
- (void)chatBarFinishedRecoding:(TLChatBar *)chatBar;
|
||||
|
||||
@end
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// TLChatBaseViewController+ChatBar.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/17.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLChatBaseViewController.h"
|
||||
#import "TLMoreKeyboard.h"
|
||||
#import "TLEmojiKeyboard.h"
|
||||
|
||||
@interface TLChatBaseViewController (ChatBar) <TLChatBarDelegate, TLKeyboardDelegate, TLEmojiKeyboardDelegate>
|
||||
|
||||
/// 表情键盘
|
||||
@property (nonatomic, strong, readonly) TLEmojiKeyboard *emojiKeyboard;
|
||||
|
||||
/// 更多键盘
|
||||
@property (nonatomic, strong, readonly) TLMoreKeyboard *moreKeyboard;
|
||||
|
||||
- (void)loadKeyboard;
|
||||
- (void)dismissKeyboard;
|
||||
|
||||
- (void)keyboardWillShow:(NSNotification *)notification;
|
||||
- (void)keyboardDidShow:(NSNotification *)notification;
|
||||
- (void)keyboardWillHide:(NSNotification *)notification;
|
||||
- (void)keyboardFrameWillChange:(NSNotification *)notification;
|
||||
|
||||
|
||||
@end
|
||||
+319
@@ -0,0 +1,319 @@
|
||||
//
|
||||
// TLChatBaseViewController+ChatBar.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/17.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLChatBaseViewController+ChatBar.h"
|
||||
#import "TLChatBaseViewController+Proxy.h"
|
||||
#import "TLChatBaseViewController+MessageDisplayView.h"
|
||||
#import "TLAudioRecorder.h"
|
||||
#import "TLAudioPlayer.h"
|
||||
#import "TLUserHelper.h"
|
||||
#import "NSFileManager+TLChat.h"
|
||||
|
||||
@implementation TLChatBaseViewController (ChatBar)
|
||||
|
||||
#pragma mark - # Public Methods
|
||||
- (void)loadKeyboard
|
||||
{
|
||||
[self.emojiKeyboard setKeyboardDelegate:self];
|
||||
[self.emojiKeyboard setDelegate:self];
|
||||
[self.moreKeyboard setKeyboardDelegate:self];
|
||||
[self.moreKeyboard setDelegate:self];
|
||||
}
|
||||
|
||||
- (void)dismissKeyboard
|
||||
{
|
||||
if (curStatus == TLChatBarStatusMore) {
|
||||
[self.moreKeyboard dismissWithAnimation:YES];
|
||||
curStatus = TLChatBarStatusInit;
|
||||
}
|
||||
else if (curStatus == TLChatBarStatusEmoji) {
|
||||
[self.emojiKeyboard dismissWithAnimation:YES];
|
||||
curStatus = TLChatBarStatusInit;
|
||||
}
|
||||
[self.chatBar resignFirstResponder];
|
||||
}
|
||||
|
||||
//MARK: 系统键盘回调
|
||||
- (void)keyboardWillShow:(NSNotification *)notification
|
||||
{
|
||||
if (curStatus != TLChatBarStatusKeyboard) {
|
||||
return;
|
||||
}
|
||||
[self.messageDisplayView scrollToBottomWithAnimation:YES];
|
||||
}
|
||||
|
||||
- (void)keyboardDidShow:(NSNotification *)notification
|
||||
{
|
||||
if (curStatus != TLChatBarStatusKeyboard) {
|
||||
return;
|
||||
}
|
||||
if (lastStatus == TLChatBarStatusMore) {
|
||||
[self.moreKeyboard dismissWithAnimation:NO];
|
||||
}
|
||||
else if (lastStatus == TLChatBarStatusEmoji) {
|
||||
[self.emojiKeyboard dismissWithAnimation:NO];
|
||||
}
|
||||
[self.messageDisplayView scrollToBottomWithAnimation:YES];
|
||||
}
|
||||
|
||||
- (void)keyboardFrameWillChange:(NSNotification *)notification
|
||||
{
|
||||
if (curStatus != TLChatBarStatusKeyboard && lastStatus != TLChatBarStatusKeyboard) {
|
||||
return;
|
||||
}
|
||||
CGRect keyboardFrame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
||||
if (lastStatus == TLChatBarStatusMore || lastStatus == TLChatBarStatusEmoji) {
|
||||
if (keyboardFrame.size.height <= HEIGHT_CHAT_KEYBOARD) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (curStatus == TLChatBarStatusEmoji || curStatus == TLChatBarStatusMore) {
|
||||
return;
|
||||
}
|
||||
[self.chatBar mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.bottom.mas_equalTo(self.view).mas_offset(-keyboardFrame.size.height);
|
||||
}];
|
||||
[self.view layoutIfNeeded];
|
||||
[self.messageDisplayView scrollToBottomWithAnimation:YES];
|
||||
}
|
||||
|
||||
- (void)keyboardWillHide:(NSNotification *)notification
|
||||
{
|
||||
if (curStatus != TLChatBarStatusKeyboard && lastStatus != TLChatBarStatusKeyboard) {
|
||||
return;
|
||||
}
|
||||
if (curStatus == TLChatBarStatusEmoji || curStatus == TLChatBarStatusMore) {
|
||||
return;
|
||||
}
|
||||
[self.chatBar mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.bottom.mas_equalTo(self.view);
|
||||
}];
|
||||
[self.view layoutIfNeeded];
|
||||
}
|
||||
|
||||
#pragma mark - Delegate
|
||||
//MARK: TLChatBarDelegate
|
||||
// 发送文本消息
|
||||
- (void)chatBar:(TLChatBar *)chatBar sendText:(NSString *)text
|
||||
{
|
||||
TLTextMessage *message = [[TLTextMessage alloc] init];
|
||||
message.text = text;
|
||||
[self sendMessage:message];
|
||||
}
|
||||
|
||||
//MARK: - 录音相关
|
||||
- (void)chatBarStartRecording:(TLChatBar *)chatBar
|
||||
{
|
||||
// 先停止播放
|
||||
if ([TLAudioPlayer sharedAudioPlayer].isPlaying) {
|
||||
[[TLAudioPlayer sharedAudioPlayer] stopPlayingAudio];
|
||||
}
|
||||
|
||||
[self.recorderIndicatorView setStatus:TLRecorderStatusRecording];
|
||||
[self.messageDisplayView addSubview:self.recorderIndicatorView];
|
||||
[self.recorderIndicatorView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.center.mas_equalTo(self.view);
|
||||
make.size.mas_equalTo(CGSizeMake(150, 150));
|
||||
}];
|
||||
|
||||
__block NSInteger time_count = 0;
|
||||
TLVoiceMessage *message = [[TLVoiceMessage alloc] init];
|
||||
message.ownerTyper = TLMessageOwnerTypeSelf;
|
||||
message.userID = [TLUserHelper sharedHelper].userID;
|
||||
message.fromUser = (id<TLChatUserProtocol>)[TLUserHelper sharedHelper].user;
|
||||
message.msgStatus = TLVoiceMessageStatusRecording;
|
||||
message.date = [NSDate date];
|
||||
[[TLAudioRecorder sharedRecorder] startRecordingWithVolumeChangedBlock:^(CGFloat volume) {
|
||||
time_count ++;
|
||||
if (time_count == 2) {
|
||||
[self addToShowMessage:message];
|
||||
}
|
||||
[self.recorderIndicatorView setVolume:volume];
|
||||
} completeBlock:^(NSString *filePath, CGFloat time) {
|
||||
if (time < 1.0) {
|
||||
[self.recorderIndicatorView setStatus:TLRecorderStatusTooShort];
|
||||
return;
|
||||
}
|
||||
[self.recorderIndicatorView removeFromSuperview];
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
|
||||
NSString *fileName = [NSString stringWithFormat:@"%.0lf.caf", [NSDate date].timeIntervalSince1970 * 1000];
|
||||
NSString *path = [NSFileManager pathUserChatVoice:fileName];
|
||||
NSError *error;
|
||||
[[NSFileManager defaultManager] moveItemAtPath:filePath toPath:path error:&error];
|
||||
if (error) {
|
||||
DDLogError(@"录音文件出错: %@", error);
|
||||
return;
|
||||
}
|
||||
|
||||
message.recFileName = fileName;
|
||||
message.time = time;
|
||||
message.msgStatus = TLVoiceMessageStatusNormal;
|
||||
[message resetMessageFrame];
|
||||
[self sendMessage:message];
|
||||
}
|
||||
} cancelBlock:^{
|
||||
[self.messageDisplayView deleteMessage:message];
|
||||
[self.recorderIndicatorView removeFromSuperview];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)chatBarWillCancelRecording:(TLChatBar *)chatBar cancel:(BOOL)cancel
|
||||
{
|
||||
[self.recorderIndicatorView setStatus:cancel ? TLRecorderStatusWillCancel : TLRecorderStatusRecording];
|
||||
}
|
||||
|
||||
- (void)chatBarFinishedRecoding:(TLChatBar *)chatBar
|
||||
{
|
||||
[[TLAudioRecorder sharedRecorder] stopRecording];
|
||||
}
|
||||
|
||||
- (void)chatBarDidCancelRecording:(TLChatBar *)chatBar
|
||||
{
|
||||
[[TLAudioRecorder sharedRecorder] cancelRecording];
|
||||
}
|
||||
|
||||
//MARK: - chatBar状态切换
|
||||
- (void)chatBar:(TLChatBar *)chatBar changeStatusFrom:(TLChatBarStatus)fromStatus to:(TLChatBarStatus)toStatus
|
||||
{
|
||||
if (curStatus == toStatus) {
|
||||
return;
|
||||
}
|
||||
lastStatus = fromStatus;
|
||||
curStatus = toStatus;
|
||||
if (toStatus == TLChatBarStatusInit) {
|
||||
if (fromStatus == TLChatBarStatusMore) {
|
||||
[self.moreKeyboard dismissWithAnimation:YES];
|
||||
}
|
||||
else if (fromStatus == TLChatBarStatusEmoji) {
|
||||
[self.emojiKeyboard dismissWithAnimation:YES];
|
||||
}
|
||||
}
|
||||
else if (toStatus == TLChatBarStatusVoice) {
|
||||
if (fromStatus == TLChatBarStatusMore) {
|
||||
[self.moreKeyboard dismissWithAnimation:YES];
|
||||
}
|
||||
else if (fromStatus == TLChatBarStatusEmoji) {
|
||||
[self.emojiKeyboard dismissWithAnimation:YES];
|
||||
}
|
||||
}
|
||||
else if (toStatus == TLChatBarStatusEmoji) {
|
||||
[self.emojiKeyboard showInView:self.view withAnimation:YES];
|
||||
}
|
||||
else if (toStatus == TLChatBarStatusMore) {
|
||||
[self.moreKeyboard showInView:self.view withAnimation:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)chatBar:(TLChatBar *)chatBar didChangeTextViewHeight:(CGFloat)height
|
||||
{
|
||||
[self.messageDisplayView scrollToBottomWithAnimation:NO];
|
||||
}
|
||||
|
||||
//MARK: TLKeyboardDelegate
|
||||
- (void)chatKeyboardWillShow:(id)keyboard animated:(BOOL)animated
|
||||
{
|
||||
[self.messageDisplayView scrollToBottomWithAnimation:YES];
|
||||
}
|
||||
|
||||
- (void)chatKeyboardDidShow:(id)keyboard animated:(BOOL)animated
|
||||
{
|
||||
if (curStatus == TLChatBarStatusMore && lastStatus == TLChatBarStatusEmoji) {
|
||||
[self.emojiKeyboard dismissWithAnimation:NO];
|
||||
}
|
||||
else if (curStatus == TLChatBarStatusEmoji && lastStatus == TLChatBarStatusMore) {
|
||||
[self.moreKeyboard dismissWithAnimation:NO];
|
||||
}
|
||||
[self.messageDisplayView scrollToBottomWithAnimation:YES];
|
||||
}
|
||||
|
||||
- (void)chatKeyboard:(id)keyboard didChangeHeight:(CGFloat)height
|
||||
{
|
||||
[self.chatBar mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.bottom.mas_equalTo(self.view).mas_offset(-height);
|
||||
}];
|
||||
[self.view layoutIfNeeded];
|
||||
[self.messageDisplayView scrollToBottomWithAnimation:YES];
|
||||
}
|
||||
|
||||
//MARK: TLEmojiKeyboardDelegate
|
||||
- (void)emojiKeyboard:(TLEmojiKeyboard *)emojiKB didSelectedEmojiItem:(TLExpressionModel *)emoji
|
||||
{
|
||||
if (emoji.type == TLEmojiTypeEmoji || emoji.type == TLEmojiTypeFace) {
|
||||
[self.chatBar addEmojiString:emoji.name];
|
||||
}
|
||||
else {
|
||||
TLExpressionMessage *message = [[TLExpressionMessage alloc] init];
|
||||
message.emoji = emoji;
|
||||
[self sendMessage:message];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)emojiKeyboardSendButtonDown
|
||||
{
|
||||
[self.chatBar sendCurrentText];
|
||||
}
|
||||
|
||||
- (void)emojiKeyboardDeleteButtonDown
|
||||
{
|
||||
[self.chatBar deleteLastCharacter];
|
||||
}
|
||||
|
||||
- (void)emojiKeyboard:(TLEmojiKeyboard *)emojiKB didTouchEmojiItem:(TLExpressionModel *)emoji atRect:(CGRect)rect
|
||||
{
|
||||
if (emoji.type == TLEmojiTypeEmoji || emoji.type == TLEmojiTypeFace) {
|
||||
if (self.emojiDisplayView.superview == nil) {
|
||||
[self.emojiKeyboard addSubview:self.emojiDisplayView];
|
||||
}
|
||||
[self.emojiDisplayView displayEmoji:emoji atRect:rect];
|
||||
}
|
||||
else {
|
||||
if (self.imageExpressionDisplayView.superview == nil) {
|
||||
[self.emojiKeyboard addSubview:self.imageExpressionDisplayView];
|
||||
}
|
||||
[self.imageExpressionDisplayView displayEmoji:emoji atRect:rect];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)emojiKeyboardCancelTouchEmojiItem:(TLEmojiKeyboard *)emojiKB
|
||||
{
|
||||
if (self.emojiDisplayView.superview != nil) {
|
||||
[self.emojiDisplayView removeFromSuperview];
|
||||
}
|
||||
else if (self.imageExpressionDisplayView.superview != nil) {
|
||||
[self.imageExpressionDisplayView removeFromSuperview];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)emojiKeyboard:(TLEmojiKeyboard *)emojiKB selectedEmojiGroupType:(TLEmojiType)type
|
||||
{
|
||||
if (type == TLEmojiTypeEmoji || type == TLEmojiTypeFace) {
|
||||
[self.chatBar setActivity:YES];
|
||||
}
|
||||
else {
|
||||
[self.chatBar setActivity:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)chatInputViewHasText
|
||||
{
|
||||
return self.chatBar.curText.length == 0 ? NO : YES;
|
||||
}
|
||||
|
||||
#pragma mark - # Getter
|
||||
- (TLEmojiKeyboard *)emojiKeyboard
|
||||
{
|
||||
return [TLEmojiKeyboard keyboard];
|
||||
}
|
||||
|
||||
- (TLMoreKeyboard *)moreKeyboard
|
||||
{
|
||||
return [TLMoreKeyboard keyboard];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// TLChatBaseViewController+MessageDisplayView.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/17.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLChatBaseViewController.h"
|
||||
#import "TLAudioPlayer.h"
|
||||
|
||||
#define MAX_SHOWTIME_MSG_COUNT 10
|
||||
#define MAX_SHOWTIME_MSG_SECOND 30
|
||||
|
||||
@interface TLChatBaseViewController (MessageDisplayView) <TLChatMessageDisplayViewDelegate>
|
||||
|
||||
/**
|
||||
* 添加展示消息(添加到chatVC)
|
||||
*/
|
||||
- (void)addToShowMessage:(TLMessage *)message;
|
||||
|
||||
- (void)resetChatTVC;
|
||||
|
||||
@end
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
//
|
||||
// TLChatBaseViewController+MessageDisplayView.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/17.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLChatBaseViewController+MessageDisplayView.h"
|
||||
#import "TLChatBaseViewController+ChatBar.h"
|
||||
#import "TLTextDisplayView.h"
|
||||
|
||||
@implementation TLChatBaseViewController (MessageDisplayView)
|
||||
|
||||
#pragma mark - # Public Methods
|
||||
- (void)addToShowMessage:(TLMessage *)message
|
||||
{
|
||||
message.showTime = [self p_needShowTime:message.date];
|
||||
[self.messageDisplayView addMessage:message];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.messageDisplayView scrollToBottomWithAnimation:YES];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)addVoiceRecordingMessage:(TLMessage *)message
|
||||
{
|
||||
message.date = [NSDate date];
|
||||
}
|
||||
|
||||
- (void)resetChatTVC
|
||||
{
|
||||
[self.messageDisplayView resetMessageView];
|
||||
lastDateInterval = 0;
|
||||
msgAccumulate = 0;
|
||||
}
|
||||
|
||||
#pragma mark - # Delegate
|
||||
//MARK: TLChatMessageDisplayViewDelegate
|
||||
// chatView 点击事件
|
||||
- (void)chatMessageDisplayViewDidTouched:(TLChatMessageDisplayView *)chatTVC
|
||||
{
|
||||
[self dismissKeyboard];
|
||||
}
|
||||
|
||||
// chatView 获取历史记录
|
||||
- (void)chatMessageDisplayView:(TLChatMessageDisplayView *)chatTVC getRecordsFromDate:(NSDate *)date count:(NSUInteger)count completed:(void (^)(NSDate *, NSArray *, BOOL))completed
|
||||
{
|
||||
TLWeakSelf(self);
|
||||
[[TLMessageManager sharedInstance] messageRecordForPartner:[self.partner chat_userID] fromDate:date count:count complete:^(NSArray *array, BOOL hasMore) {
|
||||
if (array.count > 0) {
|
||||
int count = 0;
|
||||
NSTimeInterval tm = 0;
|
||||
for (TLMessage *message in array) {
|
||||
if (++count > MAX_SHOWTIME_MSG_COUNT || tm == 0 || message.date.timeIntervalSince1970 - tm > MAX_SHOWTIME_MSG_SECOND) {
|
||||
tm = message.date.timeIntervalSince1970;
|
||||
count = 0;
|
||||
message.showTime = YES;
|
||||
}
|
||||
if (message.ownerTyper == TLMessageOwnerTypeSelf) {
|
||||
message.fromUser = weakself.user;
|
||||
}
|
||||
else {
|
||||
if ([weakself.partner chat_userType] == TLChatUserTypeUser) {
|
||||
message.fromUser = weakself.partner;
|
||||
}
|
||||
else if ([weakself.partner chat_userType] == TLChatUserTypeGroup){
|
||||
if ([weakself.partner respondsToSelector:@selector(groupMemberByID:)]) {
|
||||
message.fromUser = [weakself.partner groupMemberByID:message.friendID];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
completed(date, array, hasMore);
|
||||
}];
|
||||
}
|
||||
|
||||
- (BOOL)chatMessageDisplayView:(TLChatMessageDisplayView *)chatTVC deleteMessage:(TLMessage *)message
|
||||
{
|
||||
return [[TLMessageManager sharedInstance] deleteMessageByMsgID:message.messageID];
|
||||
}
|
||||
|
||||
- (void)chatMessageDisplayView:(TLChatMessageDisplayView *)chatTVC didClickUserAvatar:(TLUser *)user
|
||||
{
|
||||
if ([self respondsToSelector:@selector(didClickedUserAvatar:)]) {
|
||||
[self didClickedUserAvatar:user];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)chatMessageDisplayView:(TLChatMessageDisplayView *)chatTVC didDoubleClickMessage:(TLMessage *)message
|
||||
{
|
||||
if (message.messageType == TLMessageTypeText) {
|
||||
TLTextDisplayView *displayView = [[TLTextDisplayView alloc] init];
|
||||
[displayView showInView:self.navigationController.view withAttrText:[(TLTextMessage *)message attrText] animation:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)chatMessageDisplayView:(TLChatMessageDisplayView *)chatTVC didClickMessage:(TLMessage *)message
|
||||
{
|
||||
if (message.messageType == TLMessageTypeImage && [self respondsToSelector:@selector(didClickedImageMessages:atIndex:)]) {
|
||||
// 展示聊天图片
|
||||
[[TLMessageManager sharedInstance] chatImagesAndVideosForPartnerID:[self.partner chat_userID] completed:^(NSArray *imagesData) {
|
||||
NSInteger index = -1;
|
||||
for (int i = 0; i < imagesData.count; i ++) {
|
||||
if ([message.messageID isEqualToString:[imagesData[i] messageID]]) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index >= 0) {
|
||||
[self didClickedImageMessages:imagesData atIndex:index];
|
||||
}
|
||||
}];
|
||||
}
|
||||
else if (message.messageType == TLMessageTypeVoice) {
|
||||
if ([(TLVoiceMessage *)message msgStatus] == TLVoiceMessageStatusNormal) {
|
||||
// 播放语音消息
|
||||
[(TLVoiceMessage *)message setMsgStatus:TLVoiceMessageStatusPlaying];
|
||||
|
||||
[[TLAudioPlayer sharedAudioPlayer] playAudioAtPath:[(TLVoiceMessage *)message path] complete:^(BOOL finished) {
|
||||
[(TLVoiceMessage *)message setMsgStatus:TLVoiceMessageStatusNormal];
|
||||
[self.messageDisplayView updateMessage:message];
|
||||
}];
|
||||
}
|
||||
else {
|
||||
// 停止播放语音消息
|
||||
[[TLAudioPlayer sharedAudioPlayer] stopPlayingAudio];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - # Private Methods
|
||||
static NSTimeInterval lastDateInterval = 0;
|
||||
static NSInteger msgAccumulate = 0;
|
||||
- (BOOL)p_needShowTime:(NSDate *)date
|
||||
{
|
||||
if (++msgAccumulate > MAX_SHOWTIME_MSG_COUNT || lastDateInterval == 0 || date.timeIntervalSince1970 - lastDateInterval > MAX_SHOWTIME_MSG_SECOND) {
|
||||
lastDateInterval = date.timeIntervalSince1970;
|
||||
msgAccumulate = 0;
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// TLChatBaseViewController+Proxy.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/17.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLChatBaseViewController.h"
|
||||
|
||||
@interface TLChatBaseViewController (Proxy) <TLMessageManagerChatVCDelegate>
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
*/
|
||||
- (void)sendMessage:(TLMessage *)message;
|
||||
|
||||
@end
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// TLChatBaseViewController+Proxy.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/17.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLChatBaseViewController+Proxy.h"
|
||||
#import "TLChatBaseViewController+MessageDisplayView.h"
|
||||
#import "TLUserHelper.h"
|
||||
|
||||
@implementation TLChatBaseViewController (Proxy)
|
||||
|
||||
- (void)sendMessage:(TLMessage *)message
|
||||
{
|
||||
message.ownerTyper = TLMessageOwnerTypeSelf;
|
||||
message.userID = [TLUserHelper sharedHelper].userID;
|
||||
message.fromUser = (id<TLChatUserProtocol>)[TLUserHelper sharedHelper].user;
|
||||
message.date = [NSDate date];
|
||||
|
||||
if ([self.partner chat_userType] == TLChatUserTypeUser) {
|
||||
message.partnerType = TLPartnerTypeUser;
|
||||
message.friendID = [self.partner chat_userID];
|
||||
}
|
||||
else if ([self.partner chat_userType] == TLChatUserTypeGroup) {
|
||||
message.partnerType = TLPartnerTypeGroup;
|
||||
message.groupID = [self.partner chat_userID];
|
||||
}
|
||||
|
||||
if (message.messageType != TLMessageTypeVoice) {
|
||||
[self addToShowMessage:message]; // 添加到列表
|
||||
}
|
||||
else {
|
||||
[self.messageDisplayView updateMessage:message];
|
||||
}
|
||||
|
||||
[[TLMessageManager sharedInstance] sendMessage:message progress:^(TLMessage * message, CGFloat pregress) {
|
||||
|
||||
} success:^(TLMessage * message) {
|
||||
NSLog(@"send success");
|
||||
} failure:^(TLMessage * message) {
|
||||
NSLog(@"send failure");
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)didReceivedMessage:(TLMessage *)message;
|
||||
{
|
||||
if ([message.userID isEqualToString:self.user.chat_userID]) {
|
||||
[self addToShowMessage:message]; // 添加到列表
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
//
|
||||
// TLChatBaseViewController.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/15.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TLChatViewControllerProxy.h"
|
||||
#import "TLChatMessageDisplayView.h"
|
||||
#import "TLEmojiDisplayView.h"
|
||||
#import "TLImageExpressionDisplayView.h"
|
||||
#import "TLRecorderIndicatorView.h"
|
||||
|
||||
#import "TLMoreKeyboardDelegate.h"
|
||||
#import "TLMessageManager+MessageRecord.h"
|
||||
|
||||
#import "TLChatBar.h"
|
||||
#import "TLMoreKeyboardDelegate.h"
|
||||
|
||||
#import "TLChatUserProtocol.h"
|
||||
#import "TLUser.h"
|
||||
|
||||
@interface TLChatBaseViewController : UIViewController <TLChatViewControllerProxy, TLMoreKeyboardDelegate>
|
||||
{
|
||||
TLChatBarStatus lastStatus;
|
||||
TLChatBarStatus curStatus;
|
||||
}
|
||||
|
||||
/// 用户信息
|
||||
@property (nonatomic, strong) id<TLChatUserProtocol> user;
|
||||
|
||||
/// 聊天对象
|
||||
@property (nonatomic, strong) id<TLChatUserProtocol> partner;
|
||||
|
||||
/// 消息展示页面
|
||||
@property (nonatomic, strong) TLChatMessageDisplayView *messageDisplayView;
|
||||
|
||||
/// 聊天输入栏
|
||||
@property (nonatomic, strong) TLChatBar *chatBar;
|
||||
|
||||
/// emoji展示view
|
||||
@property (nonatomic, strong) TLEmojiDisplayView *emojiDisplayView;
|
||||
|
||||
/// 图片表情展示view
|
||||
@property (nonatomic, strong) TLImageExpressionDisplayView *imageExpressionDisplayView;
|
||||
|
||||
/// 录音展示view
|
||||
@property (nonatomic, strong) TLRecorderIndicatorView *recorderIndicatorView;;
|
||||
|
||||
/**
|
||||
* 设置“更多”键盘元素
|
||||
*/
|
||||
- (void)setChatMoreKeyboardData:(NSMutableArray *)moreKeyboardData;
|
||||
|
||||
/**
|
||||
* 设置“表情”键盘元素
|
||||
*/
|
||||
- (void)setChatEmojiKeyboardData:(NSMutableArray *)emojiKeyboardData;
|
||||
|
||||
/**
|
||||
* 重置chatVC
|
||||
*/
|
||||
- (void)resetChatVC;
|
||||
|
||||
/**
|
||||
* 发送图片信息
|
||||
*/
|
||||
- (void)sendImageMessage:(UIImage *)image;
|
||||
|
||||
@end
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
//
|
||||
// TLChatBaseViewController.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/15.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLChatBaseViewController.h"
|
||||
#import "TLChatBaseViewController+Proxy.h"
|
||||
#import "TLChatBaseViewController+ChatBar.h"
|
||||
#import "TLChatBaseViewController+MessageDisplayView.h"
|
||||
#import "UIImage+Size.h"
|
||||
#import "NSFileManager+TLChat.h"
|
||||
|
||||
@implementation TLChatBaseViewController
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
[super loadView];
|
||||
|
||||
[[TLMessageManager sharedInstance] setMessageDelegate:self];
|
||||
|
||||
[self.view addSubview:self.messageDisplayView];
|
||||
[self.view addSubview:self.chatBar];
|
||||
|
||||
[self p_addMasonry];
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
[self loadKeyboard];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardFrameWillChange:) name:UIKeyboardWillChangeFrameNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewWillDisappear:animated];
|
||||
[[TLAudioPlayer sharedAudioPlayer] stopPlayingAudio];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[TLMoreKeyboard keyboard] dismissWithAnimation:NO];
|
||||
[[TLEmojiKeyboard keyboard] dismissWithAnimation:NO];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
#ifdef DEBUG_MEMERY
|
||||
NSLog(@"dealloc ChatBaseVC");
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma mark - # Public Methods
|
||||
- (void)setPartner:(id<TLChatUserProtocol>)partner
|
||||
{
|
||||
if (_partner && [[_partner chat_userID] isEqualToString:[partner chat_userID]]) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.messageDisplayView scrollToBottomWithAnimation:NO];
|
||||
});
|
||||
return;
|
||||
}
|
||||
_partner = partner;
|
||||
[self.navigationItem setTitle:[_partner chat_username]];
|
||||
[self resetChatVC];
|
||||
}
|
||||
|
||||
- (void)setChatMoreKeyboardData:(NSMutableArray *)moreKeyboardData
|
||||
{
|
||||
[self.moreKeyboard setChatMoreKeyboardData:moreKeyboardData];
|
||||
}
|
||||
|
||||
- (void)setChatEmojiKeyboardData:(NSMutableArray *)emojiKeyboardData
|
||||
{
|
||||
[self.emojiKeyboard setEmojiGroupData:emojiKeyboardData];
|
||||
}
|
||||
|
||||
- (void)resetChatVC
|
||||
{
|
||||
NSString *chatViewBGImage;
|
||||
if (self.partner) {
|
||||
chatViewBGImage = [[NSUserDefaults standardUserDefaults] objectForKey:[@"CHAT_BG_" stringByAppendingString:[self.partner chat_userID]]];
|
||||
}
|
||||
if (chatViewBGImage == nil) {
|
||||
chatViewBGImage = [[NSUserDefaults standardUserDefaults] objectForKey:@"CHAT_BG_ALL"];
|
||||
if (chatViewBGImage == nil) {
|
||||
[self.view setBackgroundColor:[UIColor colorGrayCharcoalBG]];
|
||||
}
|
||||
else {
|
||||
NSString *imagePath = [NSFileManager pathUserChatBackgroundImage:chatViewBGImage];
|
||||
UIImage *image = [UIImage imageNamed:imagePath];
|
||||
[self.view setBackgroundColor:[UIColor colorWithPatternImage:image]];
|
||||
}
|
||||
}
|
||||
else {
|
||||
NSString *imagePath = [NSFileManager pathUserChatBackgroundImage:chatViewBGImage];
|
||||
UIImage *image = [UIImage imageNamed:imagePath];
|
||||
[self.view setBackgroundColor:[UIColor colorWithPatternImage:image]];
|
||||
}
|
||||
|
||||
[self resetChatTVC];
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送图片消息
|
||||
*/
|
||||
- (void)sendImageMessage:(UIImage *)image
|
||||
{
|
||||
NSData *imageData = (UIImagePNGRepresentation(image) ? UIImagePNGRepresentation(image) :UIImageJPEGRepresentation(image, 0.5));
|
||||
NSString *imageName = [NSString stringWithFormat:@"%lf.jpg", [NSDate date].timeIntervalSince1970];
|
||||
NSString *imagePath = [NSFileManager pathUserChatImage:imageName];
|
||||
[[NSFileManager defaultManager] createFileAtPath:imagePath contents:imageData attributes:nil];
|
||||
|
||||
TLImageMessage *message = [[TLImageMessage alloc] init];
|
||||
message.fromUser = self.user;
|
||||
message.ownerTyper = TLMessageOwnerTypeSelf;
|
||||
message.imagePath = imageName;
|
||||
message.imageSize = image.size;
|
||||
[self sendMessage:message];
|
||||
}
|
||||
|
||||
#pragma mark - # Private Methods
|
||||
- (void)p_addMasonry
|
||||
{
|
||||
[self.messageDisplayView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.and.left.and.right.mas_equalTo(self.view);
|
||||
make.bottom.mas_equalTo(self.chatBar.mas_top);
|
||||
}];
|
||||
[self.chatBar mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.and.right.and.bottom.mas_equalTo(self.view);
|
||||
make.height.mas_greaterThanOrEqualTo(TABBAR_HEIGHT);
|
||||
}];
|
||||
[self.view layoutIfNeeded];
|
||||
}
|
||||
|
||||
#pragma mark - # Getter
|
||||
- (TLChatMessageDisplayView *)messageDisplayView
|
||||
{
|
||||
if (_messageDisplayView == nil) {
|
||||
_messageDisplayView = [[TLChatMessageDisplayView alloc] init];
|
||||
[_messageDisplayView setDelegate:self];
|
||||
}
|
||||
return _messageDisplayView;
|
||||
}
|
||||
|
||||
- (TLChatBar *)chatBar
|
||||
{
|
||||
if (_chatBar == nil) {
|
||||
_chatBar = [[TLChatBar alloc] init];
|
||||
[_chatBar setDelegate:self];
|
||||
}
|
||||
return _chatBar;
|
||||
}
|
||||
|
||||
- (TLEmojiDisplayView *)emojiDisplayView
|
||||
{
|
||||
if (_emojiDisplayView == nil) {
|
||||
_emojiDisplayView = [[TLEmojiDisplayView alloc] init];
|
||||
}
|
||||
return _emojiDisplayView;
|
||||
}
|
||||
|
||||
- (TLImageExpressionDisplayView *)imageExpressionDisplayView
|
||||
{
|
||||
if (_imageExpressionDisplayView == nil) {
|
||||
_imageExpressionDisplayView = [[TLImageExpressionDisplayView alloc] init];
|
||||
}
|
||||
return _imageExpressionDisplayView;
|
||||
}
|
||||
|
||||
- (TLRecorderIndicatorView *)recorderIndicatorView
|
||||
{
|
||||
if (_recorderIndicatorView == nil) {
|
||||
_recorderIndicatorView = [[TLRecorderIndicatorView alloc] init];
|
||||
}
|
||||
return _recorderIndicatorView;
|
||||
}
|
||||
|
||||
@end
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// TLChatViewControllerProxy.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/5/1.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class TLUser;
|
||||
@class TLImageMessage;
|
||||
@protocol TLChatViewControllerProxy <NSObject>
|
||||
|
||||
@optional;
|
||||
- (void)didClickedUserAvatar:(TLUser *)user;
|
||||
|
||||
- (void)didClickedImageMessages:(NSArray *)imageMessages atIndex:(NSInteger)index;
|
||||
|
||||
@end
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// TLChatCellMenuView.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/16.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TLMessageConstants.h"
|
||||
|
||||
typedef NS_ENUM(NSInteger, TLChatMenuItemType) {
|
||||
TLChatMenuItemTypeCancel,
|
||||
TLChatMenuItemTypeCopy,
|
||||
TLChatMenuItemTypeDelete,
|
||||
};
|
||||
|
||||
@interface TLChatCellMenuView : UIView
|
||||
|
||||
@property (nonatomic, assign, readonly) BOOL isShow;
|
||||
|
||||
@property (nonatomic, assign) TLMessageType messageType;
|
||||
|
||||
@property (nonatomic, copy) void (^actionBlcok)();
|
||||
|
||||
- (void)showInView:(UIView *)view withMessageType:(TLMessageType)messageType rect:(CGRect)rect actionBlock:(void (^)(TLChatMenuItemType))actionBlock;
|
||||
|
||||
- (void)dismiss;
|
||||
|
||||
@end
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
//
|
||||
// TLChatCellMenuView.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/16.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLChatCellMenuView.h"
|
||||
|
||||
@interface TLChatCellMenuView ()
|
||||
|
||||
@property (nonatomic, strong) UIMenuController *menuController;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLChatCellMenuView
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self setBackgroundColor:[UIColor clearColor]];
|
||||
self.menuController = [UIMenuController sharedMenuController];
|
||||
|
||||
UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismiss)];
|
||||
[self addGestureRecognizer:tapGR];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)showInView:(UIView *)view withMessageType:(TLMessageType)messageType rect:(CGRect)rect actionBlock:(void (^)(TLChatMenuItemType))actionBlock
|
||||
{
|
||||
_isShow = YES;
|
||||
[self setFrame:view.bounds];
|
||||
[view addSubview:self];
|
||||
[self setActionBlcok:actionBlock];
|
||||
[self setMessageType:messageType];
|
||||
|
||||
[self.menuController setTargetRect:rect inView:self];
|
||||
[self becomeFirstResponder];
|
||||
[self.menuController setMenuVisible:YES animated:YES];
|
||||
}
|
||||
|
||||
- (void)setMessageType:(TLMessageType)messageType
|
||||
{
|
||||
UIMenuItem *copy = [[UIMenuItem alloc] initWithTitle:@"复制" action:@selector(copyButtonDown:)];
|
||||
UIMenuItem *transmit = [[UIMenuItem alloc] initWithTitle:@"转发" action:@selector(transmitButtonDown:)];
|
||||
UIMenuItem *collect = [[UIMenuItem alloc] initWithTitle:@"收藏" action:@selector(collectButtonDown:)];
|
||||
UIMenuItem *del = [[UIMenuItem alloc] initWithTitle:@"删除" action:@selector(deleteButtonDown:)];
|
||||
[self.menuController setMenuItems:@[copy, transmit, collect, del]];
|
||||
}
|
||||
|
||||
- (void)dismiss
|
||||
{
|
||||
_isShow = NO;
|
||||
if (self.actionBlcok) {
|
||||
self.actionBlcok(TLChatMenuItemTypeCancel);
|
||||
}
|
||||
[self.menuController setMenuVisible:NO animated:YES];
|
||||
[self removeFromSuperview];
|
||||
}
|
||||
|
||||
- (BOOL)canBecomeFirstResponder
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - Event Response -
|
||||
- (void)copyButtonDown:(UIMenuController *)sender
|
||||
{
|
||||
[self p_clickedMenuItemType:TLChatMenuItemTypeCopy];
|
||||
}
|
||||
|
||||
- (void)transmitButtonDown:(UIMenuController *)sender
|
||||
{
|
||||
[self p_clickedMenuItemType:TLChatMenuItemTypeCopy];
|
||||
}
|
||||
|
||||
- (void)collectButtonDown:(UIMenuController *)sender
|
||||
{
|
||||
[self p_clickedMenuItemType:TLChatMenuItemTypeCopy];
|
||||
}
|
||||
|
||||
- (void)deleteButtonDown:(UIMenuController *)sender
|
||||
{
|
||||
[self p_clickedMenuItemType:TLChatMenuItemTypeDelete];
|
||||
}
|
||||
|
||||
#pragma mark - Private Methods -
|
||||
- (void)p_clickedMenuItemType:(TLChatMenuItemType)type
|
||||
{
|
||||
_isShow = NO;
|
||||
[self removeFromSuperview];
|
||||
if (self.actionBlcok) {
|
||||
self.actionBlcok(type);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// TLEmojiDisplayView.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/16.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TLExpressionModel.h"
|
||||
|
||||
@interface TLEmojiDisplayView : UIImageView
|
||||
|
||||
@property (nonatomic, strong) TLExpressionModel *emoji;
|
||||
|
||||
@property (nonatomic, assign) CGRect rect;
|
||||
|
||||
- (void)displayEmoji:(TLExpressionModel *)emoji atRect:(CGRect)rect;
|
||||
|
||||
@end
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
//
|
||||
// TLEmojiDisplayView.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/16.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLEmojiDisplayView.h"
|
||||
|
||||
#define SIZE_TIPS CGSizeMake(55, 100)
|
||||
|
||||
@interface TLEmojiDisplayView ()
|
||||
|
||||
@property (nonatomic, strong) UIImageView *imageView;
|
||||
|
||||
@property (nonatomic, strong) UILabel *imageLabel;
|
||||
|
||||
@property (nonatomic, strong) UILabel *titleLabel;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLEmojiDisplayView
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:CGRectMake(0, 0, SIZE_TIPS.width, SIZE_TIPS.height)]) {
|
||||
[self setImage:[UIImage imageNamed:@"emojiKB_tips"]];
|
||||
[self addSubview:self.imageLabel];
|
||||
[self addSubview:self.imageView];
|
||||
[self addSubview:self.titleLabel];
|
||||
[self p_addMasonry];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)displayEmoji:(TLExpressionModel *)emoji atRect:(CGRect)rect
|
||||
{
|
||||
[self setRect:rect];
|
||||
[self setEmoji:emoji];
|
||||
}
|
||||
|
||||
- (void)setEmoji:(TLExpressionModel *)emoji
|
||||
{
|
||||
_emoji = emoji;
|
||||
if (emoji.type == TLEmojiTypeEmoji) {
|
||||
[self.imageLabel setHidden:NO];
|
||||
[self.imageView setHidden:YES];
|
||||
[self.titleLabel setHidden:YES];
|
||||
[self.imageLabel setText:emoji.name];
|
||||
}
|
||||
else if (emoji.type == TLEmojiTypeFace) {
|
||||
[self.imageLabel setHidden:YES];
|
||||
[self.imageView setHidden:NO];
|
||||
[self.titleLabel setHidden:NO];
|
||||
[self.imageView setImage:[UIImage imageNamed:emoji.name]];
|
||||
[self.titleLabel setText:[emoji.name substringWithRange:NSMakeRange(1, emoji.name.length - 2)]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setRect:(CGRect)rect
|
||||
{
|
||||
[self setCenterX:rect.origin.x + rect.size.width / 2];
|
||||
[self setY:rect.origin.y + rect.size.height - self.height - 5];
|
||||
}
|
||||
|
||||
#pragma mark - Private Methods -
|
||||
- (void)p_addMasonry
|
||||
{
|
||||
[self.imageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(self).mas_offset(10);
|
||||
make.left.mas_equalTo(self).mas_offset(12);
|
||||
make.right.mas_equalTo(self).mas_equalTo(-12);
|
||||
make.height.mas_equalTo(self.imageView.mas_width);
|
||||
}];
|
||||
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(self.imageView.mas_bottom).mas_offset(5);
|
||||
make.centerX.mas_equalTo(self);
|
||||
make.width.mas_lessThanOrEqualTo(self);
|
||||
}];
|
||||
[self.imageLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.and.height.and.centerX.mas_equalTo(self.imageView);
|
||||
make.top.mas_equalTo(self).mas_offset(12);
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Getter -
|
||||
- (UIImageView *)imageView
|
||||
{
|
||||
if (_imageView == nil) {
|
||||
_imageView = [[UIImageView alloc] init];
|
||||
}
|
||||
return _imageView;
|
||||
}
|
||||
|
||||
- (UILabel *)titleLabel
|
||||
{
|
||||
if (_titleLabel == nil) {
|
||||
_titleLabel = [[UILabel alloc] init];
|
||||
[_titleLabel setFont:[UIFont systemFontOfSize:12.0f]];
|
||||
[_titleLabel setTextColor:[UIColor grayColor]];
|
||||
}
|
||||
return _titleLabel;
|
||||
}
|
||||
|
||||
- (UILabel *)imageLabel
|
||||
{
|
||||
if (_imageLabel == nil) {
|
||||
_imageLabel = [[UILabel alloc] init];
|
||||
[_imageLabel setTextAlignment:NSTextAlignmentCenter];
|
||||
[_imageLabel setHidden:YES];
|
||||
[_imageLabel setFont:[UIFont systemFontOfSize:30.0f]];
|
||||
}
|
||||
return _imageLabel;
|
||||
}
|
||||
|
||||
@end
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// TLImageExpressionDisplayView.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/16.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TLExpressionModel.h"
|
||||
|
||||
@interface TLImageExpressionDisplayView : UIView
|
||||
|
||||
@property (nonatomic, strong) TLExpressionModel *emoji;
|
||||
|
||||
@property (nonatomic, assign) CGRect rect;
|
||||
|
||||
- (void)displayEmoji:(TLExpressionModel *)emoji atRect:(CGRect)rect;
|
||||
|
||||
@end
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
//
|
||||
// TLImageExpressionDisplayView.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/16.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLImageExpressionDisplayView.h"
|
||||
#import <SDWebImage/UIImage+GIF.h>
|
||||
|
||||
#define WIDTH_TIPS 150
|
||||
#define HEIGHT_TIPS 162
|
||||
#define WIDTH_CENTER 25
|
||||
#define SPACE_IMAGE 16
|
||||
|
||||
@interface TLImageExpressionDisplayView ()
|
||||
|
||||
@property (nonatomic, strong) UIImageView *bgLeftView;
|
||||
|
||||
@property (nonatomic, strong) UIImageView *bgCenterView;
|
||||
|
||||
@property (nonatomic, strong) UIImageView *bgRightView;
|
||||
|
||||
@property (nonatomic, strong) UIImageView *imageView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLImageExpressionDisplayView
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:CGRectMake(0, 0, WIDTH_TIPS, HEIGHT_TIPS)]) {
|
||||
[self addSubview:self.bgLeftView];
|
||||
[self addSubview:self.bgCenterView];
|
||||
[self addSubview:self.bgRightView];
|
||||
[self addSubview:self.imageView];
|
||||
[self p_addMasonry];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)displayEmoji:(TLExpressionModel *)emoji atRect:(CGRect)rect
|
||||
{
|
||||
[self setRect:rect];
|
||||
[self setEmoji:emoji];
|
||||
}
|
||||
|
||||
static NSString *curID;
|
||||
- (void)setEmoji:(TLExpressionModel *)emoji
|
||||
{
|
||||
if (_emoji == emoji) {
|
||||
return;
|
||||
}
|
||||
_emoji = emoji;
|
||||
curID = emoji.eId;
|
||||
NSData *data = [NSData dataWithContentsOfFile:emoji.path];
|
||||
if (data) {
|
||||
[self.imageView setImage:[UIImage sd_animatedGIFWithData:data]];
|
||||
}
|
||||
else {
|
||||
NSString *urlString = [TLExpressionModel expressionDownloadURLWithEid:emoji.eId];
|
||||
[self.imageView tt_setImageWithURL:TLURL(emoji.url) completed:^(UIImage *image, NSError *error, TLImageCacheType cacheType, NSURL *imageURL) {
|
||||
if ([urlString containsString:curID]) {
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
NSData *data = [NSData dataWithContentsOfURL:TLURL(urlString)];
|
||||
if ([urlString containsString:curID]) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.imageView setImage:[UIImage sd_animatedGIFWithData:data]];
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setRect:(CGRect)rect
|
||||
{
|
||||
self.y = rect.origin.y - self.height + 3;
|
||||
CGFloat w = WIDTH_TIPS - WIDTH_CENTER;
|
||||
CGFloat centerX = rect.origin.x + rect.size.width / 2;
|
||||
if (rect.origin.x + rect.size.width < self.width) { // 箭头在左边
|
||||
self.centerX = centerX + (WIDTH_TIPS - w / 4 - WIDTH_CENTER) / 2 - SPACE_IMAGE;
|
||||
[self.bgLeftView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.mas_equalTo(w / 4);
|
||||
}];
|
||||
}
|
||||
else if (SCREEN_WIDTH - rect.origin.x < self.width) { // 箭头在右边
|
||||
self.centerX = centerX - (WIDTH_TIPS - w / 4 - WIDTH_CENTER) / 2 + SPACE_IMAGE;
|
||||
[self.bgLeftView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.mas_equalTo(w / 4 * 3);
|
||||
}];
|
||||
}
|
||||
else {
|
||||
self.centerX = centerX;
|
||||
[self.bgLeftView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.mas_equalTo(w / 2);
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Private Methods -
|
||||
- (void)p_addMasonry
|
||||
{
|
||||
[self.bgLeftView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.and.left.and.bottom.mas_equalTo(self);
|
||||
}];
|
||||
[self.bgCenterView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.mas_equalTo(self.bgLeftView.mas_right);
|
||||
make.top.and.bottom.mas_equalTo(self.bgLeftView);
|
||||
make.width.mas_equalTo(WIDTH_CENTER);
|
||||
}];
|
||||
[self.bgRightView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.mas_equalTo(self.bgCenterView.mas_right);
|
||||
make.top.and.bottom.mas_equalTo(self.bgLeftView);
|
||||
make.right.mas_equalTo(self);
|
||||
}];
|
||||
[self.imageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(self).mas_offset(10);
|
||||
make.left.mas_equalTo(self).mas_offset(10);
|
||||
make.right.mas_equalTo(self).mas_offset(-10);
|
||||
make.height.mas_equalTo(self.imageView.mas_width);
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Getter -
|
||||
- (UIImageView *)imageView
|
||||
{
|
||||
if (_imageView == nil) {
|
||||
_imageView = [[UIImageView alloc] init];
|
||||
}
|
||||
return _imageView;
|
||||
}
|
||||
|
||||
- (UIImageView *)bgLeftView
|
||||
{
|
||||
if (_bgLeftView == nil) {
|
||||
_bgLeftView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"emojiKB_bigTips_left"]];
|
||||
}
|
||||
return _bgLeftView;
|
||||
}
|
||||
|
||||
- (UIImageView *)bgCenterView
|
||||
{
|
||||
if (_bgCenterView == nil) {
|
||||
_bgCenterView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"emojiKB_bigTips_middle"]];
|
||||
}
|
||||
return _bgCenterView;
|
||||
}
|
||||
|
||||
- (UIImageView *)bgRightView
|
||||
{
|
||||
if (_bgRightView == nil) {
|
||||
_bgRightView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"emojiKB_bigTips_right"]];
|
||||
}
|
||||
return _bgRightView;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// TLRecorderIndicatorView.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/7/12.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
typedef NS_ENUM(NSInteger, TLRecorderStatus) {
|
||||
TLRecorderStatusRecording,
|
||||
TLRecorderStatusWillCancel,
|
||||
TLRecorderStatusTooShort,
|
||||
};
|
||||
|
||||
@interface TLRecorderIndicatorView : UIView
|
||||
|
||||
@property (nonatomic, assign) TLRecorderStatus status;
|
||||
|
||||
/**
|
||||
* 音量大小,取值(0-1)
|
||||
*/
|
||||
@property (nonatomic, assign) CGFloat volume;
|
||||
|
||||
@end
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
//
|
||||
// TLRecorderIndicatorView.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/7/12.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLRecorderIndicatorView.h"
|
||||
|
||||
#define STR_RECORDING @"手指上滑,取消发送"
|
||||
#define STR_CANCEL @"手指松开,取消发送"
|
||||
#define STR_REC_SHORT @"说话时间太短"
|
||||
|
||||
@interface TLRecorderIndicatorView ()
|
||||
|
||||
@property (nonatomic, strong) UIView *backgroundView;
|
||||
|
||||
@property (nonatomic, strong) UILabel *titleLabel;
|
||||
|
||||
@property (nonatomic, strong) UIView *titleBackgroundView;
|
||||
|
||||
@property (nonatomic, strong) UIImageView *recImageView;
|
||||
|
||||
@property (nonatomic, strong) UIImageView *centerImageView;
|
||||
|
||||
@property (nonatomic, strong) UIImageView *volumeImageView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLRecorderIndicatorView
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self addSubview:self.backgroundView];
|
||||
[self addSubview:self.recImageView];
|
||||
[self addSubview:self.volumeImageView];
|
||||
[self addSubview:self.centerImageView];
|
||||
[self addSubview:self.titleBackgroundView];
|
||||
[self addSubview:self.titleLabel];
|
||||
|
||||
[self p_addMasonry];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setStatus:(TLRecorderStatus)status
|
||||
{
|
||||
if (status == TLRecorderStatusWillCancel) {
|
||||
[self.centerImageView setHidden:NO];
|
||||
[self.centerImageView setImage:[UIImage imageNamed:@"chat_record_cancel"]];
|
||||
[self.titleBackgroundView setHidden:NO];
|
||||
[self.recImageView setHidden:YES];
|
||||
[self.volumeImageView setHidden:YES];
|
||||
[self.titleLabel setText:STR_CANCEL];
|
||||
}
|
||||
else if (status == TLRecorderStatusRecording) {
|
||||
[self.centerImageView setHidden:YES];
|
||||
[self.titleBackgroundView setHidden:YES];
|
||||
[self.recImageView setHidden:NO];
|
||||
[self.volumeImageView setHidden:NO];
|
||||
[self.titleLabel setText:STR_RECORDING];
|
||||
}
|
||||
else if (status == TLRecorderStatusTooShort) {
|
||||
[self.centerImageView setHidden:NO];
|
||||
[self.centerImageView setImage:[UIImage imageNamed:@"chat_record_cancel"]];
|
||||
[self.titleBackgroundView setHidden:YES];
|
||||
[self.recImageView setHidden:YES];
|
||||
[self.volumeImageView setHidden:YES];
|
||||
[self.titleLabel setText:STR_REC_SHORT];
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
if (status == TLRecorderStatusTooShort) {
|
||||
[self removeFromSuperview];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setVolume:(CGFloat)volume
|
||||
{
|
||||
_volume = volume;
|
||||
NSInteger picId = 10 * (volume < 0 ? 0 : (volume > 1.0 ? 1.0 : volume));
|
||||
picId = picId > 8 ? 8 : picId;
|
||||
[self.volumeImageView setImage:[UIImage imageNamed:[NSString stringWithFormat:@"chat_record_signal_%ld", (long)picId]]];
|
||||
}
|
||||
|
||||
#pragma mark - # Private Methods
|
||||
- (void)p_addMasonry
|
||||
{
|
||||
[self.backgroundView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.mas_equalTo(0);
|
||||
}];
|
||||
[self.recImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(15);
|
||||
make.left.mas_equalTo(21);
|
||||
}];
|
||||
[self.volumeImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.and.height.mas_equalTo(self.recImageView);
|
||||
make.right.mas_equalTo(-21);
|
||||
}];
|
||||
[self.centerImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.mas_equalTo(0);
|
||||
make.top.mas_equalTo(15);
|
||||
}];
|
||||
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.mas_equalTo(0);
|
||||
make.bottom.mas_equalTo(-15);
|
||||
}];
|
||||
[self.titleBackgroundView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.mas_equalTo(self.titleLabel).mas_offset(UIEdgeInsetsMake(-2, -5, -2, -5)).priorityLow();
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - # Getter
|
||||
- (UIView *)backgroundView
|
||||
{
|
||||
if (_backgroundView == nil) {
|
||||
_backgroundView = [[UIView alloc] init];
|
||||
[_backgroundView setBackgroundColor:[UIColor blackColor]];
|
||||
[_backgroundView setAlpha:0.6f];
|
||||
[_backgroundView.layer setMasksToBounds:YES];
|
||||
[_backgroundView.layer setCornerRadius:5.0f];
|
||||
}
|
||||
return _backgroundView;
|
||||
}
|
||||
|
||||
- (UILabel *)titleLabel
|
||||
{
|
||||
if (_titleLabel == nil) {
|
||||
_titleLabel = [[UILabel alloc] init];
|
||||
[_titleLabel setFont:[UIFont systemFontOfSize:14.0f]];
|
||||
[_titleLabel setTextAlignment:NSTextAlignmentCenter];
|
||||
[_titleLabel setTextColor:[UIColor whiteColor]];
|
||||
[_titleLabel setText:STR_RECORDING];
|
||||
}
|
||||
return _titleLabel;
|
||||
}
|
||||
|
||||
- (UIView *)titleBackgroundView
|
||||
{
|
||||
if (_titleBackgroundView == nil) {
|
||||
_titleBackgroundView = [[UIView alloc] init];
|
||||
[_titleBackgroundView setHidden:YES];
|
||||
[_titleBackgroundView setBackgroundColor:[UIColor redColor]];
|
||||
[_titleBackgroundView.layer setMasksToBounds:YES];
|
||||
[_titleBackgroundView.layer setCornerRadius:2.0f];
|
||||
}
|
||||
return _titleBackgroundView;
|
||||
}
|
||||
|
||||
- (UIImageView *)recImageView
|
||||
{
|
||||
if (_recImageView == nil) {
|
||||
_recImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"chat_record_recording"]];
|
||||
}
|
||||
return _recImageView;
|
||||
}
|
||||
|
||||
- (UIImageView *)centerImageView
|
||||
{
|
||||
if (_centerImageView == nil) {
|
||||
_centerImageView = [[UIImageView alloc] init];
|
||||
[_centerImageView setHidden:YES];
|
||||
}
|
||||
return _centerImageView;
|
||||
}
|
||||
|
||||
- (UIImageView *)volumeImageView
|
||||
{
|
||||
if (_volumeImageView == nil) {
|
||||
_volumeImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"chat_record_signal_1"]];
|
||||
}
|
||||
return _volumeImageView;
|
||||
}
|
||||
|
||||
@end
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// TLTextDisplayView.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/16.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface TLTextDisplayView : UIView
|
||||
|
||||
@property (nonatomic, strong) NSAttributedString *attrString;
|
||||
|
||||
- (void)showInView:(UIView *)view withAttrText:(NSAttributedString *)attrText animation:(BOOL)animation;
|
||||
|
||||
@end
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
//
|
||||
// TLTextDisplayView.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/16.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLTextDisplayView.h"
|
||||
|
||||
#define WIDTH_TEXTVIEW self.width * 0.94
|
||||
|
||||
@interface TLTextDisplayView ()
|
||||
|
||||
@property (nonatomic, strong) UITextView *textView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLTextDisplayView
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self setBackgroundColor:[UIColor whiteColor]];
|
||||
[self addSubview:self.textView];
|
||||
[self.textView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.center.mas_equalTo(self);
|
||||
}];
|
||||
|
||||
UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismiss)];
|
||||
[self addGestureRecognizer:tapGR];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)showInView:(UIView *)view withAttrText:(NSAttributedString *)attrText animation:(BOOL)animation
|
||||
{
|
||||
[view addSubview:self];
|
||||
[self setFrame:view.bounds];
|
||||
[self setAttrString:attrText];
|
||||
[self setAlpha:0];
|
||||
[UIView animateWithDuration:0.1 animations:^{
|
||||
[self setAlpha:1.0];
|
||||
} completion:^(BOOL finished) {
|
||||
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setAttrString:(NSAttributedString *)attrString
|
||||
{
|
||||
_attrString = attrString;
|
||||
NSMutableAttributedString *mutableAttrString = [[NSMutableAttributedString alloc] initWithAttributedString:attrString];
|
||||
[mutableAttrString addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:25.0f] range:NSMakeRange(0, attrString.length)];
|
||||
[self.textView setAttributedText:mutableAttrString];
|
||||
CGSize size = [self.textView sizeThatFits:CGSizeMake(WIDTH_TEXTVIEW, MAXFLOAT)];
|
||||
size.height = size.height > SCREEN_HEIGHT ? SCREEN_HEIGHT : size.height;
|
||||
[self.textView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.size.mas_equalTo(size);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)dismiss
|
||||
{
|
||||
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];
|
||||
[UIView animateWithDuration:0.2 animations:^{
|
||||
self.alpha = 0;
|
||||
} completion:^(BOOL finished) {
|
||||
[self removeFromSuperview];
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Getter -
|
||||
- (UITextView *)textView
|
||||
{
|
||||
if (_textView == nil) {
|
||||
_textView = [[UITextView alloc] init];
|
||||
[_textView setBackgroundColor:[UIColor clearColor]];
|
||||
[_textView setTextAlignment:NSTextAlignmentCenter];
|
||||
[_textView setEditable:NO];
|
||||
}
|
||||
return _textView;
|
||||
}
|
||||
|
||||
@end
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// TLExpressionMessageCell.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/19.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLMessageBaseCell.h"
|
||||
#import "TLExpressionMessage.h"
|
||||
|
||||
@interface TLExpressionMessageCell : TLMessageBaseCell
|
||||
|
||||
@end
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
//
|
||||
// TLExpressionMessageCell.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/19.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLExpressionMessageCell.h"
|
||||
#import <SDWebImage/UIImage+GIF.h>
|
||||
#import "NSFileManager+TLChat.h"
|
||||
|
||||
@interface TLExpressionMessageCell ()
|
||||
|
||||
@property (nonatomic, strong) UIImageView *msgImageView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLExpressionMessageCell
|
||||
|
||||
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
|
||||
{
|
||||
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
|
||||
[self.contentView addSubview:self.msgImageView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setMessage:(TLExpressionMessage *)message
|
||||
{
|
||||
[self.msgImageView setAlpha:1.0]; // 取消长按效果
|
||||
// if (self.message && [self.message.messageID isEqualToString:message.messageID]) {
|
||||
// return;
|
||||
// }
|
||||
TLMessageOwnerType lastOwnType = self.message ? self.message.ownerTyper : -1;
|
||||
[super setMessage:message];
|
||||
|
||||
NSData *data = [NSData dataWithContentsOfFile:message.path];
|
||||
if (data) {
|
||||
[self.msgImageView setImage:[UIImage imageNamed:message.path]];
|
||||
[self.msgImageView setImage:[UIImage sd_animatedGIFWithData:data]];
|
||||
}
|
||||
else { // 表情组被删掉,先从缓存目录中查找,没有的话在下载并存入缓存目录
|
||||
NSString *cachePath = [NSFileManager cacheForFile:[NSString stringWithFormat:@"%@_%@.gif", message.emoji.gid, message.emoji.eId]];
|
||||
NSData *data = [NSData dataWithContentsOfFile:cachePath];
|
||||
if (data) {
|
||||
[self.msgImageView setImage:[UIImage imageNamed:cachePath]];
|
||||
[self.msgImageView setImage:[UIImage sd_animatedGIFWithData:data]];
|
||||
}
|
||||
else {
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[self.msgImageView tt_setImageWithURL:TLURL(message.url) completed:^(UIImage *image, NSError *error, TLImageCacheType cacheType, NSURL *imageURL) {
|
||||
if ([[imageURL description] isEqualToString:[(TLExpressionMessage *)weakSelf.message url]]) {
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
NSData *data = [NSData dataWithContentsOfURL:imageURL];
|
||||
[data writeToFile:cachePath atomically:NO]; // 再写入到缓存中
|
||||
if ([[imageURL description] isEqualToString:[(TLExpressionMessage *)weakSelf.message url]]) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[weakSelf.msgImageView setImage:[UIImage sd_animatedGIFWithData:data]];
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
if (lastOwnType != message.ownerTyper) {
|
||||
if (message.ownerTyper == TLMessageOwnerTypeSelf) {
|
||||
[self.msgImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(self.usernameLabel.mas_bottom).mas_offset(5);
|
||||
make.right.mas_equalTo(self.messageBackgroundView).mas_offset(-10);
|
||||
}];
|
||||
}
|
||||
else if (message.ownerTyper == TLMessageOwnerTypeFriend){
|
||||
[self.msgImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(self.usernameLabel.mas_bottom).mas_offset(5);
|
||||
make.left.mas_equalTo(self.messageBackgroundView).mas_offset(10);
|
||||
}];
|
||||
}
|
||||
}
|
||||
[self.msgImageView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.size.mas_equalTo(message.messageFrame.contentSize);
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Event Response -
|
||||
- (void)longPressMsgBGView:(UIGestureRecognizer *)gestureRecognizer
|
||||
{
|
||||
if (gestureRecognizer.state != UIGestureRecognizerStateBegan) {
|
||||
return;
|
||||
}
|
||||
[self.msgImageView setAlpha:0.7]; // 比较low的选中效果
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(messageCellLongPress:rect:)]) {
|
||||
CGRect rect = self.msgImageView.frame;
|
||||
[self.delegate messageCellLongPress:self.message rect:rect];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)doubleTabpMsgBGView
|
||||
{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(messageCellDoubleClick:)]) {
|
||||
[self.delegate messageCellDoubleClick:self.message];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Getter -
|
||||
- (UIImageView *)msgImageView
|
||||
{
|
||||
if (_msgImageView == nil) {
|
||||
_msgImageView = [[UIImageView alloc] init];
|
||||
[_msgImageView setUserInteractionEnabled:YES];
|
||||
|
||||
UILongPressGestureRecognizer *longPressGR = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressMsgBGView:)];
|
||||
[_msgImageView addGestureRecognizer:longPressGR];
|
||||
|
||||
UITapGestureRecognizer *doubleTapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTabpMsgBGView)];
|
||||
[doubleTapGR setNumberOfTapsRequired:2];
|
||||
[_msgImageView addGestureRecognizer:doubleTapGR];
|
||||
}
|
||||
return _msgImageView;
|
||||
}
|
||||
|
||||
@end
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// TLImageMessageCell.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/14.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLMessageBaseCell.h"
|
||||
#import "TLImageMessage.h"
|
||||
|
||||
@interface TLImageMessageCell : TLMessageBaseCell
|
||||
|
||||
@end
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
//
|
||||
// TLImageMessageCell.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/14.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLImageMessageCell.h"
|
||||
#import "TLMessageImageView.h"
|
||||
#import "NSFileManager+TLChat.h"
|
||||
|
||||
#define MSG_SPACE_TOP 2
|
||||
|
||||
@interface TLImageMessageCell ()
|
||||
|
||||
@property (nonatomic, strong) TLMessageImageView *msgImageView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLImageMessageCell
|
||||
|
||||
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
|
||||
{
|
||||
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
|
||||
[self.contentView addSubview:self.msgImageView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setMessage:(TLImageMessage *)message
|
||||
{
|
||||
[self.msgImageView setAlpha:1.0]; // 取消长按效果
|
||||
if (self.message && [self.message.messageID isEqualToString:message.messageID]) {
|
||||
return;
|
||||
}
|
||||
TLMessageOwnerType lastOwnType = self.message ? self.message.ownerTyper : -1;
|
||||
[super setMessage:message];
|
||||
|
||||
if ([message imagePath]) {
|
||||
NSString *imagePath = [NSFileManager pathUserChatImage:[message imagePath]];
|
||||
[self.msgImageView setThumbnailPath:imagePath highDefinitionImageURL:[message imagePath]];
|
||||
}
|
||||
else {
|
||||
[self.msgImageView setThumbnailPath:nil highDefinitionImageURL:[message imagePath]];
|
||||
[self.msgImageView tt_setImageWithURL:[NSURL URLWithString:[message imageURL]]];
|
||||
}
|
||||
|
||||
if (lastOwnType != message.ownerTyper) {
|
||||
if (message.ownerTyper == TLMessageOwnerTypeSelf) {
|
||||
[self.msgImageView setBackgroundImage:[UIImage imageNamed:@"message_sender_bg"]];
|
||||
[self.msgImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(self.messageBackgroundView);
|
||||
make.right.mas_equalTo(self.messageBackgroundView);
|
||||
}];
|
||||
}
|
||||
else if (message.ownerTyper == TLMessageOwnerTypeFriend){
|
||||
[self.msgImageView setBackgroundImage:[UIImage imageNamed:@"message_receiver_bg"]];
|
||||
[self.msgImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(self.messageBackgroundView);
|
||||
make.left.mas_equalTo(self.messageBackgroundView);
|
||||
}];
|
||||
}
|
||||
}
|
||||
[self.msgImageView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.size.mas_equalTo(message.messageFrame.contentSize);
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Event Response -
|
||||
- (void)tapMessageView
|
||||
{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(messageCellTap:)]) {
|
||||
[self.delegate messageCellTap:self.message];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)longPressMsgBGView:(UIGestureRecognizer *)gestureRecognizer
|
||||
{
|
||||
if (gestureRecognizer.state != UIGestureRecognizerStateBegan) {
|
||||
return;
|
||||
}
|
||||
[self.msgImageView setAlpha:0.7]; // 比较low的选中效果
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(messageCellLongPress:rect:)]) {
|
||||
CGRect rect = self.msgImageView.frame;
|
||||
rect.size.height -= 10; // 北京图片底部空白区域
|
||||
[self.delegate messageCellLongPress:self.message rect:rect];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)doubleTabpMsgBGView
|
||||
{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(messageCellDoubleClick:)]) {
|
||||
[self.delegate messageCellDoubleClick:self.message];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Getter -
|
||||
- (TLMessageImageView *)msgImageView
|
||||
{
|
||||
if (_msgImageView == nil) {
|
||||
_msgImageView = [[TLMessageImageView alloc] init];
|
||||
[_msgImageView setUserInteractionEnabled:YES];
|
||||
|
||||
UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapMessageView)];
|
||||
[_msgImageView addGestureRecognizer:tapGR];
|
||||
|
||||
UILongPressGestureRecognizer *longPressGR = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressMsgBGView:)];
|
||||
[_msgImageView addGestureRecognizer:longPressGR];
|
||||
|
||||
UITapGestureRecognizer *doubleTapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTabpMsgBGView)];
|
||||
[doubleTapGR setNumberOfTapsRequired:2];
|
||||
[_msgImageView addGestureRecognizer:doubleTapGR];
|
||||
}
|
||||
return _msgImageView;
|
||||
}
|
||||
|
||||
@end
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// TLMessageBaseCell.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/1.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TLMessageCellDelegate.h"
|
||||
#import "TLMessage.h"
|
||||
|
||||
@interface TLMessageBaseCell : UITableViewCell
|
||||
|
||||
@property (nonatomic, assign) id<TLMessageCellDelegate>delegate;
|
||||
|
||||
@property (nonatomic, strong) UILabel *timeLabel;
|
||||
|
||||
@property (nonatomic, strong) UIButton *avatarButton;
|
||||
|
||||
@property (nonatomic, strong) UILabel *usernameLabel;
|
||||
|
||||
@property (nonatomic, strong) UIImageView *messageBackgroundView;
|
||||
|
||||
@property (nonatomic, strong) TLMessage *message;
|
||||
|
||||
/**
|
||||
* 更新消息,如果子类不重写,默认调用setMessage方法
|
||||
*/
|
||||
- (void)updateMessage:(TLMessage *)message;
|
||||
|
||||
@end
|
||||
+221
@@ -0,0 +1,221 @@
|
||||
//
|
||||
// TLMessageBaseCell.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/1.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLMessageBaseCell.h"
|
||||
#import "NSDate+TLChat.h"
|
||||
#import "NSFileManager+TLChat.h"
|
||||
|
||||
#define TIMELABEL_HEIGHT 20.0f
|
||||
#define TIMELABEL_SPACE_Y 10.0f
|
||||
|
||||
#define NAMELABEL_HEIGHT 14.0f
|
||||
#define NAMELABEL_SPACE_X 12.0f
|
||||
#define NAMELABEL_SPACE_Y 1.0f
|
||||
|
||||
#define AVATAR_WIDTH 40.0f
|
||||
#define AVATAR_SPACE_X 8.0f
|
||||
#define AVATAR_SPACE_Y 12.0f
|
||||
|
||||
#define MSGBG_SPACE_X 5.0f
|
||||
#define MSGBG_SPACE_Y 1.0f
|
||||
|
||||
@interface TLMessageBaseCell ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLMessageBaseCell
|
||||
|
||||
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
|
||||
{
|
||||
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
|
||||
[self setBackgroundColor:[UIColor clearColor]];
|
||||
[self setSelectionStyle:UITableViewCellSelectionStyleNone];
|
||||
[self.contentView addSubview:self.timeLabel];
|
||||
[self.contentView addSubview:self.avatarButton];
|
||||
[self.contentView addSubview:self.usernameLabel];
|
||||
[self.contentView addSubview:self.messageBackgroundView];
|
||||
[self p_addMasonry];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setMessage:(TLMessage *)message
|
||||
{
|
||||
if (_message && [_message.messageID isEqualToString:message.messageID]) {
|
||||
return;
|
||||
}
|
||||
[self.timeLabel setText:[NSString stringWithFormat:@" %@ ", message.date.chatTimeInfo]];
|
||||
[self.usernameLabel setText:[message.fromUser chat_username]];
|
||||
if ([message.fromUser chat_avatarPath].length > 0) {
|
||||
NSString *path = [NSFileManager pathUserAvatar:[message.fromUser chat_avatarPath]];
|
||||
[self.avatarButton setImage:[UIImage imageNamed:path] forState:UIControlStateNormal];
|
||||
}
|
||||
else {
|
||||
[self.avatarButton tt_setImageWithURL:TLURL([message.fromUser chat_avatarURL]) forState:UIControlStateNormal];
|
||||
}
|
||||
|
||||
// 时间
|
||||
if (!_message || _message.showTime != message.showTime) {
|
||||
[self.timeLabel mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.height.mas_equalTo(message.showTime ? TIMELABEL_HEIGHT : 0);
|
||||
make.top.mas_equalTo(self.contentView).mas_offset(message.showTime ? TIMELABEL_SPACE_Y : 0);
|
||||
}];
|
||||
}
|
||||
|
||||
if (!message || _message.ownerTyper != message.ownerTyper) {
|
||||
// 头像
|
||||
[self.avatarButton mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.and.height.mas_equalTo(AVATAR_WIDTH);
|
||||
make.top.mas_equalTo(self.timeLabel.mas_bottom).mas_offset(AVATAR_SPACE_Y);
|
||||
if(message.ownerTyper == TLMessageOwnerTypeSelf) {
|
||||
make.right.mas_equalTo(self.contentView).mas_offset(-AVATAR_SPACE_X);
|
||||
}
|
||||
else {
|
||||
make.left.mas_equalTo(self.contentView).mas_offset(AVATAR_SPACE_X);
|
||||
}
|
||||
}];
|
||||
|
||||
// 用户名
|
||||
[self.usernameLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(self.avatarButton).mas_equalTo(-NAMELABEL_SPACE_Y);
|
||||
if (message.ownerTyper == TLMessageOwnerTypeSelf) {
|
||||
make.right.mas_equalTo(self.avatarButton.mas_left).mas_offset(- NAMELABEL_SPACE_X);
|
||||
}
|
||||
else {
|
||||
make.left.mas_equalTo(self.avatarButton.mas_right).mas_equalTo(NAMELABEL_SPACE_X);
|
||||
}
|
||||
}];
|
||||
|
||||
// 背景
|
||||
[self.messageBackgroundView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
message.ownerTyper == TLMessageOwnerTypeSelf ? make.right.mas_equalTo(self.avatarButton.mas_left).mas_offset(-MSGBG_SPACE_X) : make.left.mas_equalTo(self.avatarButton.mas_right).mas_offset(MSGBG_SPACE_X);
|
||||
make.top.mas_equalTo(self.usernameLabel.mas_bottom).mas_offset(message.showName ? 0 : -MSGBG_SPACE_Y);
|
||||
}];
|
||||
}
|
||||
|
||||
[self.usernameLabel setHidden:!message.showName];
|
||||
[self.usernameLabel mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.height.mas_equalTo(message.showName ? NAMELABEL_HEIGHT : 0);
|
||||
}];
|
||||
|
||||
_message = message;
|
||||
}
|
||||
|
||||
- (void)updateMessage:(TLMessage *)message
|
||||
{
|
||||
[self setMessage:message];
|
||||
}
|
||||
|
||||
#pragma mark - Private Methods -
|
||||
- (void)p_addMasonry
|
||||
{
|
||||
[self.timeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(self.contentView).mas_offset(TIMELABEL_SPACE_Y);
|
||||
make.centerX.mas_equalTo(self.contentView);
|
||||
}];
|
||||
|
||||
[self.usernameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(self.avatarButton).mas_equalTo(-NAMELABEL_SPACE_Y);
|
||||
make.right.mas_equalTo(self.avatarButton.mas_left).mas_offset(- NAMELABEL_SPACE_X);
|
||||
}];
|
||||
|
||||
// Default - self
|
||||
[self.avatarButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.mas_equalTo(self.contentView).mas_offset(-AVATAR_SPACE_X);
|
||||
make.width.and.height.mas_equalTo(AVATAR_WIDTH);
|
||||
make.top.mas_equalTo(self.timeLabel.mas_bottom).mas_offset(AVATAR_SPACE_Y);
|
||||
}];
|
||||
|
||||
[self.messageBackgroundView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.mas_equalTo(self.avatarButton.mas_left).mas_offset(-MSGBG_SPACE_X);
|
||||
make.top.mas_equalTo(self.usernameLabel.mas_bottom).mas_offset(-MSGBG_SPACE_Y);
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Event Response -
|
||||
- (void)avatarButtonDown:(UIButton *)sender
|
||||
{
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(messageCellDidClickAvatarForUser:)]) {
|
||||
[_delegate messageCellDidClickAvatarForUser:self.message.fromUser];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)longPressMsgBGView:(UIGestureRecognizer *)gestureRecognizer
|
||||
{
|
||||
if (gestureRecognizer.state != UIGestureRecognizerStateBegan) {
|
||||
return;
|
||||
}
|
||||
[self.messageBackgroundView setHighlighted:YES];
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(messageCellLongPress:rect:)]) {
|
||||
CGRect rect = self.messageBackgroundView.frame;
|
||||
rect.size.height -= 10; // 北京图片底部空白区域
|
||||
[_delegate messageCellLongPress:self.message rect:rect];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)doubleTabpMsgBGView
|
||||
{
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(messageCellDoubleClick:)]) {
|
||||
[_delegate messageCellDoubleClick:self.message];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Getter -
|
||||
- (UILabel *)timeLabel
|
||||
{
|
||||
if (_timeLabel == nil) {
|
||||
_timeLabel = [[UILabel alloc] init];
|
||||
[_timeLabel setFont:[UIFont systemFontOfSize:12.0f]];
|
||||
[_timeLabel setTextColor:[UIColor whiteColor]];
|
||||
[_timeLabel setBackgroundColor:[UIColor grayColor]];
|
||||
[_timeLabel setAlpha:0.7f];
|
||||
[_timeLabel.layer setMasksToBounds:YES];
|
||||
[_timeLabel.layer setCornerRadius:5.0f];
|
||||
}
|
||||
return _timeLabel;
|
||||
}
|
||||
|
||||
- (UIButton *)avatarButton
|
||||
{
|
||||
if (_avatarButton == nil) {
|
||||
_avatarButton = [[UIButton alloc] init];
|
||||
[_avatarButton.layer setMasksToBounds:YES];
|
||||
[_avatarButton.layer setBorderWidth:BORDER_WIDTH_1PX];
|
||||
[_avatarButton.layer setBorderColor:[UIColor colorWithWhite:0.7 alpha:1.0].CGColor];
|
||||
[_avatarButton addTarget:self action:@selector(avatarButtonDown:) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _avatarButton;
|
||||
}
|
||||
|
||||
- (UILabel *)usernameLabel
|
||||
{
|
||||
if (_usernameLabel == nil) {
|
||||
_usernameLabel = [[UILabel alloc] init];
|
||||
[_usernameLabel setTextColor:[UIColor grayColor]];
|
||||
[_usernameLabel setFont:[UIFont systemFontOfSize:12.0f]];
|
||||
}
|
||||
return _usernameLabel;
|
||||
}
|
||||
|
||||
- (UIImageView *)messageBackgroundView
|
||||
{
|
||||
if (_messageBackgroundView == nil) {
|
||||
_messageBackgroundView = [[UIImageView alloc] init];
|
||||
[_messageBackgroundView setUserInteractionEnabled:YES];
|
||||
|
||||
UILongPressGestureRecognizer *longPressGR = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressMsgBGView:)];
|
||||
[_messageBackgroundView addGestureRecognizer:longPressGR];
|
||||
|
||||
UITapGestureRecognizer *doubleTapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTabpMsgBGView)];
|
||||
[doubleTapGR setNumberOfTapsRequired:2];
|
||||
[_messageBackgroundView addGestureRecognizer:doubleTapGR];
|
||||
}
|
||||
return _messageBackgroundView;
|
||||
}
|
||||
|
||||
@end
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
|
||||
//
|
||||
// TLMessageCellDelegate.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/2.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@protocol TLChatUserProtocol;
|
||||
@class TLMessage;
|
||||
@protocol TLMessageCellDelegate <NSObject>
|
||||
|
||||
- (void)messageCellDidClickAvatarForUser:(id<TLChatUserProtocol>)user;
|
||||
|
||||
- (void)messageCellTap:(TLMessage *)message;
|
||||
|
||||
- (void)messageCellLongPress:(TLMessage *)message rect:(CGRect)rect;
|
||||
|
||||
- (void)messageCellDoubleClick:(TLMessage *)message;
|
||||
|
||||
@end
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// TLMessageImageView.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/15.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface TLMessageImageView : UIImageView
|
||||
|
||||
@property (nonatomic, strong) UIImage *backgroundImage;
|
||||
|
||||
/**
|
||||
* 设置消息图片(规则:收到消息时,先下载缩略图到本地,再添加到列表显示,并自动下载大图)
|
||||
*
|
||||
* @param imagePath 缩略图Path
|
||||
* @param imageURL 高清图URL
|
||||
*/
|
||||
- (void)setThumbnailPath:(NSString *)imagePath highDefinitionImageURL:(NSString *)imageURL;
|
||||
|
||||
@end
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// TLMessageImageView.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/15.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLMessageImageView.h"
|
||||
|
||||
@interface TLMessageImageView ()
|
||||
|
||||
@property (nonatomic, weak) CAShapeLayer *maskLayer;
|
||||
|
||||
@property (nonatomic, weak) CALayer *contentLayer;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLMessageImageView
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
CAShapeLayer *maskLayer = [CAShapeLayer layer];
|
||||
maskLayer.contentsCenter = CGRectMake(0.5, 0.6, 0.1, 0.1);
|
||||
maskLayer.contentsScale = [UIScreen mainScreen].scale; //非常关键设置自动拉伸的效果且不变形
|
||||
CALayer *contentLayer = [[CALayer alloc] init];
|
||||
[contentLayer setMask:maskLayer];
|
||||
[self.layer addSublayer:contentLayer];
|
||||
|
||||
self.maskLayer = maskLayer;
|
||||
self.contentLayer = contentLayer;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
NSLog(@"delloc TLMessageImageView");
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
[self.maskLayer setFrame:CGRectMake(0, 0, self.width, self.height)];
|
||||
[self.contentLayer setFrame:CGRectMake(0, 0, self.width, self.height)];
|
||||
}
|
||||
|
||||
- (void)setThumbnailPath:(NSString *)imagePath highDefinitionImageURL:(NSString *)imageURL
|
||||
{
|
||||
if (imagePath == nil) {
|
||||
[self.contentLayer setContents:nil];
|
||||
}
|
||||
else {
|
||||
UIImage *image = [[UIImage imageNamed:imagePath] copy];
|
||||
[self.contentLayer setContents:(id)(image.CGImage)];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setBackgroundImage:(UIImage *)backgroundImage
|
||||
{
|
||||
UIImage *image = [backgroundImage copy];
|
||||
[self.maskLayer setContents:(id)image.CGImage];
|
||||
}
|
||||
|
||||
@end
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// TLTextMessageCell.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/1.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLMessageBaseCell.h"
|
||||
#import "TLTextMessage.h"
|
||||
|
||||
@interface TLTextMessageCell : TLMessageBaseCell
|
||||
|
||||
|
||||
@end
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
//
|
||||
// TLTextMessageCell.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/1.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLTextMessageCell.h"
|
||||
|
||||
#define MSG_SPACE_TOP 14
|
||||
#define MSG_SPACE_BTM 20
|
||||
#define MSG_SPACE_LEFT 19
|
||||
#define MSG_SPACE_RIGHT 22
|
||||
|
||||
@interface TLTextMessageCell ()
|
||||
|
||||
@property (nonatomic, strong) UILabel *messageLabel;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLTextMessageCell
|
||||
|
||||
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
|
||||
{
|
||||
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
|
||||
[self.contentView addSubview:self.messageLabel];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setMessage:(TLTextMessage *)message
|
||||
{
|
||||
if (self.message && [self.message.messageID isEqualToString:message.messageID]) {
|
||||
return;
|
||||
}
|
||||
TLMessageOwnerType lastOwnType = self.message ? self.message.ownerTyper : -1;
|
||||
[super setMessage:message];
|
||||
[self.messageLabel setAttributedText:[message attrText]];
|
||||
|
||||
[self.messageLabel setContentCompressionResistancePriority:500 forAxis:UILayoutConstraintAxisHorizontal];
|
||||
[self.messageBackgroundView setContentCompressionResistancePriority:100 forAxis:UILayoutConstraintAxisHorizontal];
|
||||
if (lastOwnType != message.ownerTyper) {
|
||||
if (message.ownerTyper == TLMessageOwnerTypeSelf) {
|
||||
[self.messageBackgroundView setImage:[UIImage imageNamed:@"message_sender_bg"]];
|
||||
[self.messageBackgroundView setHighlightedImage:[UIImage imageNamed:@"message_sender_bgHL"]];
|
||||
|
||||
[self.messageLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.mas_equalTo(self.messageBackgroundView).mas_offset(-MSG_SPACE_RIGHT);
|
||||
make.top.mas_equalTo(self.messageBackgroundView).mas_offset(MSG_SPACE_TOP);
|
||||
}];
|
||||
[self.messageBackgroundView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.mas_equalTo(self.messageLabel).mas_offset(-MSG_SPACE_LEFT);
|
||||
make.bottom.mas_equalTo(self.messageLabel).mas_offset(MSG_SPACE_BTM);
|
||||
}];
|
||||
}
|
||||
else if (message.ownerTyper == TLMessageOwnerTypeFriend){
|
||||
[self.messageBackgroundView setImage:[UIImage imageNamed:@"message_receiver_bg"]];
|
||||
[self.messageBackgroundView setHighlightedImage:[UIImage imageNamed:@"message_receiver_bgHL"]];
|
||||
|
||||
[self.messageLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.mas_equalTo(self.messageBackgroundView).mas_offset(MSG_SPACE_LEFT);
|
||||
make.top.mas_equalTo(self.messageBackgroundView).mas_offset(MSG_SPACE_TOP);
|
||||
}];
|
||||
[self.messageBackgroundView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.mas_equalTo(self.messageLabel).mas_offset(MSG_SPACE_RIGHT);
|
||||
make.bottom.mas_equalTo(self.messageLabel).mas_offset(MSG_SPACE_BTM);
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
[self.messageLabel mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.size.mas_equalTo(message.messageFrame.contentSize);
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Getter -
|
||||
- (UILabel *)messageLabel
|
||||
{
|
||||
if (_messageLabel == nil) {
|
||||
_messageLabel = [[UILabel alloc] init];
|
||||
[_messageLabel setFont:[UIFont fontTextMessageText]];
|
||||
[_messageLabel setNumberOfLines:0];
|
||||
}
|
||||
return _messageLabel;
|
||||
}
|
||||
|
||||
@end
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// TLVoiceImageView.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/7/11.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface TLVoiceImageView : UIImageView
|
||||
|
||||
@property (nonatomic, assign) BOOL isFromMe;
|
||||
|
||||
- (void)startPlayingAnimation;
|
||||
|
||||
- (void)stopPlayingAnimation;
|
||||
|
||||
@end
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
//
|
||||
// TLVoiceImageView.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/7/11.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLVoiceImageView.h"
|
||||
|
||||
@interface TLVoiceImageView ()
|
||||
|
||||
@property (nonatomic, strong) NSArray *imagesArray;
|
||||
|
||||
@property (nonatomic, strong) UIImage *normalImage;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLVoiceImageView
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self setIsFromMe:YES];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setIsFromMe:(BOOL)isFromMe
|
||||
{
|
||||
_isFromMe = isFromMe;
|
||||
if (isFromMe) {
|
||||
self.imagesArray = @[[UIImage imageNamed:@"message_voice_sender_playing_1"],
|
||||
[UIImage imageNamed:@"message_voice_sender_playing_2"],
|
||||
[UIImage imageNamed:@"message_voice_sender_playing_3"]];
|
||||
self.normalImage = [UIImage imageNamed:@"message_voice_sender_normal"];
|
||||
}
|
||||
else {
|
||||
self.imagesArray = @[[UIImage imageNamed:@"message_voice_receiver_playing_1"],
|
||||
[UIImage imageNamed:@"message_voice_receiver_playing_2"],
|
||||
[UIImage imageNamed:@"message_voice_receiver_playing_3"]];
|
||||
self.normalImage = [UIImage imageNamed:@"message_voice_receiver_normal"];
|
||||
}
|
||||
[self setImage:self.normalImage];
|
||||
}
|
||||
|
||||
- (void)startPlayingAnimation
|
||||
{
|
||||
self.animationImages = self.imagesArray;
|
||||
self.animationRepeatCount = 0;
|
||||
self.animationDuration = 1.0;
|
||||
[self startAnimating];
|
||||
}
|
||||
|
||||
- (void)stopPlayingAnimation
|
||||
{
|
||||
[self stopAnimating];
|
||||
}
|
||||
|
||||
@end
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// TLVoiceMessageCell.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/5/6.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLMessageBaseCell.h"
|
||||
#import "TLVoiceMessage.h"
|
||||
|
||||
@interface TLVoiceMessageCell : TLMessageBaseCell
|
||||
|
||||
@end
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
//
|
||||
// TLVoiceMessageCell.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/5/6.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLVoiceMessageCell.h"
|
||||
#import "TLVoiceImageView.h"
|
||||
|
||||
@interface TLVoiceMessageCell ()
|
||||
|
||||
@property (nonatomic, strong) UILabel *voiceTimeLabel;
|
||||
|
||||
@property (nonatomic, strong) TLVoiceImageView *voiceImageView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLVoiceMessageCell
|
||||
|
||||
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
|
||||
{
|
||||
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
|
||||
[self.contentView addSubview:self.voiceTimeLabel];
|
||||
[self.messageBackgroundView addSubview:self.voiceImageView];
|
||||
|
||||
UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapMsgBGView)];
|
||||
[self.messageBackgroundView addGestureRecognizer:tapGR];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setMessage:(TLVoiceMessage *)message
|
||||
{
|
||||
TLMessageOwnerType lastOwnType = self.message ? self.message.ownerTyper : -1;
|
||||
[super setMessage:message];
|
||||
|
||||
[self.voiceTimeLabel setText:[NSString stringWithFormat:@"%.0lf\"\n", message.time]];
|
||||
|
||||
if (lastOwnType != message.ownerTyper) {
|
||||
if (message.ownerTyper == TLMessageOwnerTypeSelf) {
|
||||
[self.voiceImageView setIsFromMe:YES];
|
||||
[self.messageBackgroundView setImage:[UIImage imageNamed:@"message_sender_bg"]];
|
||||
[self.messageBackgroundView setHighlightedImage:[UIImage imageNamed:@"message_sender_bgHL"]];
|
||||
|
||||
[self.voiceTimeLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.mas_equalTo(self.messageBackgroundView.mas_left);
|
||||
make.top.mas_equalTo(self.messageBackgroundView.mas_centerY).mas_offset(-5);
|
||||
}];
|
||||
[self.voiceImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.mas_equalTo(-13);
|
||||
make.centerY.mas_equalTo(self.avatarButton);
|
||||
}];
|
||||
}
|
||||
else if (message.ownerTyper == TLMessageOwnerTypeFriend){
|
||||
[self.voiceImageView setIsFromMe:NO];
|
||||
[self.messageBackgroundView setImage:[UIImage imageNamed:@"message_receiver_bg"]];
|
||||
[self.messageBackgroundView setHighlightedImage:[UIImage imageNamed:@"message_receiver_bgHL"]];
|
||||
[self.voiceTimeLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.mas_equalTo(self.messageBackgroundView.mas_right);
|
||||
make.top.mas_equalTo(self.messageBackgroundView.mas_centerY).mas_offset(-5);
|
||||
}];
|
||||
[self.voiceImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.mas_equalTo(13);
|
||||
make.centerY.mas_equalTo(self.avatarButton);
|
||||
}];
|
||||
}
|
||||
}
|
||||
[self.messageBackgroundView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.size.mas_equalTo(message.messageFrame.contentSize);
|
||||
}];
|
||||
|
||||
if (message.msgStatus == TLVoiceMessageStatusRecording) {
|
||||
[self.voiceTimeLabel setHidden:YES];
|
||||
[self.voiceImageView setHidden:YES];
|
||||
[self p_startRecordingAnimation];
|
||||
}
|
||||
else {
|
||||
[self.voiceTimeLabel setHidden:NO];
|
||||
[self.voiceImageView setHidden:NO];
|
||||
[self p_stopRecordingAnimation];
|
||||
[self.messageBackgroundView setAlpha:1.0];
|
||||
}
|
||||
message.msgStatus == TLVoiceMessageStatusPlaying ? [self.voiceImageView startPlayingAnimation] : [self.voiceImageView stopPlayingAnimation];
|
||||
}
|
||||
|
||||
- (void)updateMessage:(TLVoiceMessage *)message
|
||||
{
|
||||
[super setMessage:message];
|
||||
|
||||
[self.voiceTimeLabel setText:[NSString stringWithFormat:@"%.0lf\"\n", message.time]];
|
||||
if (message.msgStatus == TLVoiceMessageStatusRecording) {
|
||||
[self.voiceTimeLabel setHidden:YES];
|
||||
[self.voiceImageView setHidden:YES];
|
||||
[self p_startRecordingAnimation];
|
||||
}
|
||||
else {
|
||||
[self.voiceTimeLabel setHidden:NO];
|
||||
[self.voiceImageView setHidden:NO];
|
||||
[self p_stopRecordingAnimation];
|
||||
}
|
||||
message.msgStatus == TLVoiceMessageStatusPlaying ? [self.voiceImageView startPlayingAnimation] : [self.voiceImageView stopPlayingAnimation];
|
||||
|
||||
[UIView animateWithDuration:0.5 animations:^{
|
||||
[self.messageBackgroundView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.size.mas_equalTo(message.messageFrame.contentSize);
|
||||
}];
|
||||
[self layoutIfNeeded];
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - # Event Response
|
||||
- (void)didTapMsgBGView
|
||||
{
|
||||
[self.voiceImageView startPlayingAnimation];
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(messageCellTap:)]) {
|
||||
[self.delegate messageCellTap:self.message];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - # Private Methods
|
||||
static bool isStartAnimation = NO;
|
||||
static float bgAlpha = 1.0;
|
||||
- (void)p_startRecordingAnimation
|
||||
{
|
||||
isStartAnimation = YES;
|
||||
bgAlpha = 0.4;
|
||||
[self p_repeatAnimation];
|
||||
}
|
||||
|
||||
- (void)p_repeatAnimation
|
||||
{
|
||||
[UIView animateWithDuration:1.0 animations:^{
|
||||
[self.messageBackgroundView setAlpha:bgAlpha];
|
||||
} completion:^(BOOL finished) {
|
||||
if (finished) {
|
||||
bgAlpha = bgAlpha > 0.9 ? 0.4 : 1.0;
|
||||
if (isStartAnimation) {
|
||||
[self p_repeatAnimation];
|
||||
}
|
||||
else {
|
||||
[self.messageBackgroundView setAlpha:1.0];
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)p_stopRecordingAnimation
|
||||
{
|
||||
isStartAnimation = NO;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - # Getter
|
||||
- (UILabel *)voiceTimeLabel
|
||||
{
|
||||
if (_voiceTimeLabel == nil) {
|
||||
_voiceTimeLabel = [[UILabel alloc] init];
|
||||
[_voiceTimeLabel setTextColor:[UIColor grayColor]];
|
||||
[_voiceTimeLabel setFont:[UIFont systemFontOfSize:14.0f]];
|
||||
}
|
||||
return _voiceTimeLabel;
|
||||
}
|
||||
|
||||
- (TLVoiceImageView *)voiceImageView
|
||||
{
|
||||
if (_voiceImageView == nil) {
|
||||
_voiceImageView = [[TLVoiceImageView alloc] init];
|
||||
}
|
||||
return _voiceImageView;
|
||||
}
|
||||
|
||||
@end
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// TLChatMessageDisplayView+Delegate.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/17.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLChatMessageDisplayView.h"
|
||||
#import "TLTextMessageCell.h"
|
||||
#import "TLImageMessageCell.h"
|
||||
#import "TLExpressionMessageCell.h"
|
||||
#import "TLVoiceMessageCell.h"
|
||||
|
||||
@interface TLChatMessageDisplayView (Delegate) <UITableViewDelegate, UITableViewDataSource, TLMessageCellDelegate, TLActionSheetDelegate>
|
||||
|
||||
- (void)registerCellClassForTableView:(UITableView *)tableView;
|
||||
|
||||
@end
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
//
|
||||
// TLChatMessageDisplayView+Delegate.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/17.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLChatMessageDisplayView+Delegate.h"
|
||||
#import "TLTextDisplayView.h"
|
||||
#import "TLChatEventStatistics.h"
|
||||
|
||||
@implementation TLChatMessageDisplayView (Delegate)
|
||||
|
||||
#pragma mark - # Public Methods
|
||||
- (void)registerCellClassForTableView:(UITableView *)tableView
|
||||
{
|
||||
[tableView registerClass:[TLTextMessageCell class] forCellReuseIdentifier:@"TLTextMessageCell"];
|
||||
[tableView registerClass:[TLImageMessageCell class] forCellReuseIdentifier:@"TLImageMessageCell"];
|
||||
[tableView registerClass:[TLExpressionMessageCell class] forCellReuseIdentifier:@"TLExpressionMessageCell"];
|
||||
[tableView registerClass:[TLVoiceMessageCell class] forCellReuseIdentifier:@"TLVoiceMessageCell"];
|
||||
[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"EmptyCell"];
|
||||
}
|
||||
|
||||
#pragma mark - # Delegate
|
||||
//MARK: UITableViewDataSouce
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
return self.data.count;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
TLMessage * message = self.data[indexPath.row];
|
||||
if (message.messageType == TLMessageTypeText) {
|
||||
TLTextMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TLTextMessageCell"];
|
||||
[cell setMessage:message];
|
||||
[cell setDelegate:self];
|
||||
return cell;
|
||||
}
|
||||
else if (message.messageType == TLMessageTypeImage) {
|
||||
TLImageMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TLImageMessageCell"];
|
||||
[cell setMessage:message];
|
||||
[cell setDelegate:self];
|
||||
return cell;
|
||||
}
|
||||
else if (message.messageType == TLMessageTypeExpression) {
|
||||
TLExpressionMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TLExpressionMessageCell"];
|
||||
[cell setMessage:message];
|
||||
[cell setDelegate:self];
|
||||
return cell;
|
||||
}
|
||||
else if (message.messageType == TLMessageTypeVoice) {
|
||||
TLVoiceMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TLVoiceMessageCell"];
|
||||
[cell setMessage:message];
|
||||
[cell setDelegate:self];
|
||||
return cell;
|
||||
}
|
||||
|
||||
return [tableView dequeueReusableCellWithIdentifier:@"EmptyCell"];
|
||||
}
|
||||
|
||||
//MARK: UITableViewDelegate
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(nonnull NSIndexPath *)indexPath
|
||||
{
|
||||
if (indexPath.row >= self.data.count) {
|
||||
return 0.0f;
|
||||
}
|
||||
TLMessage * message = self.data[indexPath.row];
|
||||
return message.messageFrame.height;
|
||||
}
|
||||
|
||||
//MARK: TLMessageCellDelegate
|
||||
- (void)messageCellDidClickAvatarForUser:(TLUser *)user
|
||||
{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(chatMessageDisplayView:didClickUserAvatar:)]) {
|
||||
[self.delegate chatMessageDisplayView:self didClickUserAvatar:user];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)messageCellTap:(TLMessage *)message
|
||||
{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(chatMessageDisplayView:didClickMessage:)]) {
|
||||
[self.delegate chatMessageDisplayView:self didClickMessage:message];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 双击Message Cell
|
||||
*/
|
||||
- (void)messageCellDoubleClick:(TLMessage *)message
|
||||
{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(chatMessageDisplayView:didDoubleClickMessage:)]) {
|
||||
[self.delegate chatMessageDisplayView:self didDoubleClickMessage:message];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)messageCellLongPress:(TLMessage *)message rect:(CGRect)rect
|
||||
{
|
||||
NSInteger row = [self.data indexOfObject:message];
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];
|
||||
if (self.disableLongPressMenu) {
|
||||
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
|
||||
return;
|
||||
}
|
||||
|
||||
CGRect cellRect = [self.tableView rectForRowAtIndexPath:indexPath];
|
||||
rect.origin.y += cellRect.origin.y - self.tableView.contentOffset.y;
|
||||
__weak typeof(self)weakSelf = self;
|
||||
[self.menuView showInView:self withMessageType:message.messageType rect:rect actionBlock:^(TLChatMenuItemType type) {
|
||||
[weakSelf.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
|
||||
if (type == TLChatMenuItemTypeCopy) {
|
||||
NSString *str = [message messageCopy];
|
||||
[[UIPasteboard generalPasteboard] setString:str];
|
||||
}
|
||||
else if (type == TLChatMenuItemTypeDelete) {
|
||||
TLActionSheet *actionSheet = [[TLActionSheet alloc] initWithTitle:@"是否删除该条消息" delegate:weakSelf cancelButtonTitle:@"取消" destructiveButtonTitle:@"确定" otherButtonTitles: nil];
|
||||
actionSheet.tag = [weakSelf.data indexOfObject:message];
|
||||
[actionSheet show];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
//MARK: UIScrollViewDelegate
|
||||
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
|
||||
{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(chatMessageDisplayViewDidTouched:)]) {
|
||||
[self.delegate chatMessageDisplayViewDidTouched:self];
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: TLActionSheetDelegate
|
||||
- (void)actionSheet:(TLActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
|
||||
{
|
||||
if (buttonIndex == 0) {
|
||||
TLMessage * message = [self.data objectAtIndex:actionSheet.tag];
|
||||
[self p_deleteMessage:message];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - # Private Methods
|
||||
- (void)p_deleteMessage:(TLMessage *)message
|
||||
{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(chatMessageDisplayView:deleteMessage:)]) {
|
||||
BOOL ok = [self.delegate chatMessageDisplayView:self deleteMessage:message];
|
||||
if (ok) {
|
||||
[self deleteMessage:message withAnimation:YES];
|
||||
[MobClick event:EVENT_DELETE_MESSAGE];
|
||||
}
|
||||
else {
|
||||
[TLUIUtility showAlertWithTitle:@"错误" message:@"从数据库中删除消息失败。"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// TLChatMessageDisplayView.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/9.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TLChatMessageDisplayViewDelegate.h"
|
||||
#import "TLChatCellMenuView.h"
|
||||
|
||||
#import "TLTextMessage.h"
|
||||
#import "TLImageMessage.h"
|
||||
#import "TLExpressionMessage.h"
|
||||
#import "TLVoiceMessage.h"
|
||||
|
||||
|
||||
@interface TLChatMessageDisplayView : UIView
|
||||
|
||||
@property (nonatomic, assign) id<TLChatMessageDisplayViewDelegate>delegate;
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray *data;
|
||||
|
||||
@property (nonatomic, strong, readonly) UITableView *tableView;
|
||||
|
||||
/// 禁用下拉刷新
|
||||
@property (nonatomic, assign) BOOL disablePullToRefresh;
|
||||
|
||||
/// 禁用长按菜单
|
||||
@property (nonatomic, assign) BOOL disableLongPressMenu;
|
||||
|
||||
@property (nonatomic, strong) TLChatCellMenuView *menuView;
|
||||
|
||||
|
||||
/**
|
||||
* 发送消息(在列表展示)
|
||||
*/
|
||||
- (void)addMessage:(TLMessage *)message;
|
||||
|
||||
/**
|
||||
* 删除消息
|
||||
*/
|
||||
- (void)deleteMessage:(TLMessage *)message;
|
||||
- (void)deleteMessage:(TLMessage *)message withAnimation:(BOOL)animation;
|
||||
|
||||
/**
|
||||
* 更新消息状态
|
||||
*/
|
||||
- (void)updateMessage:(TLMessage *)message;
|
||||
- (void)reloadData;
|
||||
|
||||
/**
|
||||
* 滚动到底部
|
||||
*
|
||||
* @param animation 是否执行动画
|
||||
*/
|
||||
- (void)scrollToBottomWithAnimation:(BOOL)animation;
|
||||
|
||||
/**
|
||||
* 重新加载聊天信息
|
||||
*/
|
||||
- (void)resetMessageView;
|
||||
|
||||
@end
|
||||
+247
@@ -0,0 +1,247 @@
|
||||
//
|
||||
// TLChatMessageDisplayView.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/9.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLChatMessageDisplayView.h"
|
||||
#import "TLChatMessageDisplayView+Delegate.h"
|
||||
#import <MJRefresh/MJRefresh.h>
|
||||
#import "TLMessageBaseCell.h"
|
||||
#import "TLChatEventStatistics.h"
|
||||
|
||||
#define PAGE_MESSAGE_COUNT 15
|
||||
|
||||
@interface TLChatMessageDisplayView ()
|
||||
|
||||
@property (nonatomic, strong) MJRefreshNormalHeader *refresHeader;
|
||||
|
||||
/// 用户决定新消息是否显示时间
|
||||
@property (nonatomic, strong) NSDate *curDate;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLChatMessageDisplayView
|
||||
@synthesize tableView = _tableView;
|
||||
@synthesize data = _data;
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self addSubview:self.tableView];
|
||||
[self setDisablePullToRefresh:NO];
|
||||
[self registerCellClassForTableView:self.tableView];
|
||||
|
||||
[self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.mas_equalTo(0);
|
||||
}];
|
||||
|
||||
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTouchTableView)];
|
||||
[self.tableView addGestureRecognizer:tap];
|
||||
|
||||
[self.tableView addObserver:self forKeyPath:@"bounds" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self.menuView dismiss];
|
||||
[self.tableView removeObserver:self forKeyPath:@"bounds"];
|
||||
#ifdef DEBUG_MEMERY
|
||||
NSLog(@"dealloc MessageDisplayView");
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma mark - # Public Methods
|
||||
- (void)resetMessageView
|
||||
{
|
||||
[self.data removeAllObjects];
|
||||
[self.tableView reloadData];
|
||||
self.curDate = [NSDate date];
|
||||
if (!self.disablePullToRefresh) {
|
||||
[self.tableView setMj_header:self.refresHeader];
|
||||
}
|
||||
TLWeakSelf(self);
|
||||
[self p_tryToRefreshMoreRecord:^(NSInteger count, BOOL hasMore) {
|
||||
if (!hasMore) {
|
||||
weakself.tableView.mj_header = nil;
|
||||
}
|
||||
if (count > 0) {
|
||||
[weakself.tableView reloadData];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[weakself.tableView scrollToBottomWithAnimation:NO];
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)addMessage:(TLMessage *)message
|
||||
{
|
||||
[self.data addObject:message];
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
- (void)setData:(NSMutableArray *)data
|
||||
{
|
||||
_data = data;
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
- (void)deleteMessage:(TLMessage *)message
|
||||
{
|
||||
[self deleteMessage:message withAnimation:YES];
|
||||
}
|
||||
|
||||
- (void)deleteMessage:(TLMessage *)message withAnimation:(BOOL)animation
|
||||
{
|
||||
if (message == nil) {
|
||||
return;
|
||||
}
|
||||
NSInteger index = [self.data indexOfObject:message];
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(chatMessageDisplayView:deleteMessage:)]) {
|
||||
BOOL ok = [self.delegate chatMessageDisplayView:self deleteMessage:message];
|
||||
if (ok) {
|
||||
[self.data removeObject:message];
|
||||
[self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:index inSection:0]] withRowAnimation:animation ? UITableViewRowAnimationAutomatic : UITableViewRowAnimationNone];
|
||||
[MobClick event:EVENT_DELETE_MESSAGE];
|
||||
}
|
||||
else {
|
||||
[TLUIUtility showAlertWithTitle:@"错误" message:@"从数据库中删除消息失败。"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateMessage:(TLMessage *)message
|
||||
{
|
||||
NSArray *visibleCells = [self.tableView visibleCells];
|
||||
for (id cell in visibleCells) {
|
||||
if ([cell isKindOfClass:[TLMessageBaseCell class]]) {
|
||||
if ([[(TLMessageBaseCell *)cell message].messageID isEqualToString:message.messageID]) {
|
||||
[cell updateMessage:message];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)reloadData
|
||||
{
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
- (void)scrollToBottomWithAnimation:(BOOL)animation
|
||||
{
|
||||
[self.tableView scrollToBottomWithAnimation:animation];
|
||||
}
|
||||
|
||||
- (void)setDisablePullToRefresh:(BOOL)disablePullToRefresh
|
||||
{
|
||||
if (disablePullToRefresh) {
|
||||
[self.tableView setMj_header:nil];
|
||||
}
|
||||
else {
|
||||
[self.tableView setMj_header:self.refresHeader];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - # Event Response
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
|
||||
{
|
||||
if (object == self.tableView && [keyPath isEqualToString:@"bounds"]) { // tableView变小时,消息贴底
|
||||
CGRect oldBounds, newBounds;
|
||||
[change[@"old"] getValue:&oldBounds];
|
||||
[change[@"new"] getValue:&newBounds];
|
||||
CGFloat t = oldBounds.size.height - newBounds.size.height;
|
||||
if (t > 0 && fabs(self.tableView.contentOffset.y + t + newBounds.size.height - self.tableView.contentSize.height) < 1.0) {
|
||||
[self scrollToBottomWithAnimation:NO];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)didTouchTableView
|
||||
{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(chatMessageDisplayViewDidTouched:)]) {
|
||||
[self.delegate chatMessageDisplayViewDidTouched:self];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - # Private Methods
|
||||
/**
|
||||
* 获取聊天历史记录
|
||||
*/
|
||||
- (void)p_tryToRefreshMoreRecord:(void (^)(NSInteger count, BOOL hasMore))complete
|
||||
{
|
||||
TLWeakSelf(self);
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(chatMessageDisplayView:getRecordsFromDate:count:completed:)]) {
|
||||
[self.delegate chatMessageDisplayView:self
|
||||
getRecordsFromDate:self.curDate
|
||||
count:PAGE_MESSAGE_COUNT
|
||||
completed:^(NSDate *date, NSArray *array, BOOL hasMore) {
|
||||
if (array.count > 0 && [date isEqualToDate:weakself.curDate]) {
|
||||
weakself.curDate = [array[0] date];
|
||||
[weakself.data insertObjects:array atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, array.count)]];
|
||||
complete(array.count, hasMore);
|
||||
}
|
||||
else {
|
||||
complete(0, hasMore);
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - # Getter
|
||||
- (UITableView *)tableView
|
||||
{
|
||||
if (_tableView == nil) {
|
||||
_tableView = [[UITableView alloc] init];
|
||||
[_tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
|
||||
[_tableView setBackgroundColor:[UIColor clearColor]];
|
||||
[_tableView setTableFooterView:[[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 10)]];
|
||||
[_tableView setDelegate:self];
|
||||
[_tableView setDataSource:self];
|
||||
}
|
||||
return _tableView;
|
||||
}
|
||||
|
||||
- (TLChatCellMenuView *)menuView
|
||||
{
|
||||
if (!_menuView) {
|
||||
_menuView = [[TLChatCellMenuView alloc] init];
|
||||
}
|
||||
return _menuView;
|
||||
}
|
||||
|
||||
- (NSMutableArray *)data
|
||||
{
|
||||
if (_data == nil) {
|
||||
_data = [[NSMutableArray alloc] init];
|
||||
}
|
||||
return _data;
|
||||
}
|
||||
|
||||
- (MJRefreshNormalHeader *)refresHeader
|
||||
{
|
||||
if (_refresHeader == nil) {
|
||||
TLWeakSelf(self);
|
||||
_refresHeader = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
|
||||
[weakself p_tryToRefreshMoreRecord:^(NSInteger count, BOOL hasMore) {
|
||||
[weakself.tableView.mj_header endRefreshing];
|
||||
if (!hasMore) {
|
||||
weakself.tableView.mj_header = nil;
|
||||
}
|
||||
if (count > 0) {
|
||||
[weakself.tableView reloadData];
|
||||
[weakself.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:count inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
|
||||
}
|
||||
}];
|
||||
}];
|
||||
_refresHeader.lastUpdatedTimeLabel.hidden = YES;
|
||||
_refresHeader.stateLabel.hidden = YES;
|
||||
}
|
||||
return _refresHeader;
|
||||
}
|
||||
|
||||
@end
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// TLChatMessageDisplayViewDelegate.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/23.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class TLUser;
|
||||
@class TLMessage;
|
||||
@class TLChatMessageDisplayView;
|
||||
@protocol TLChatMessageDisplayViewDelegate <NSObject>
|
||||
|
||||
/**
|
||||
* 聊天界面点击事件,用于收键盘
|
||||
*/
|
||||
- (void)chatMessageDisplayViewDidTouched:(TLChatMessageDisplayView *)chatTVC;
|
||||
|
||||
/**
|
||||
* 下拉刷新,获取某个时间段的聊天记录(异步)
|
||||
*
|
||||
* @param chatTVC chatTVC
|
||||
* @param date 开始时间
|
||||
* @param count 条数
|
||||
* @param completed 结果Blcok
|
||||
*/
|
||||
- (void)chatMessageDisplayView:(TLChatMessageDisplayView *)chatTVC
|
||||
getRecordsFromDate:(NSDate *)date
|
||||
count:(NSUInteger)count
|
||||
completed:(void (^)(NSDate *, NSArray *, BOOL))completed;
|
||||
|
||||
@optional
|
||||
/**
|
||||
* 消息长按删除
|
||||
*
|
||||
* @return 删除是否成功
|
||||
*/
|
||||
- (BOOL)chatMessageDisplayView:(TLChatMessageDisplayView *)chatTVC
|
||||
deleteMessage:(TLMessage *)message;
|
||||
|
||||
/**
|
||||
* 用户头像点击事件
|
||||
*/
|
||||
- (void)chatMessageDisplayView:(TLChatMessageDisplayView *)chatTVC
|
||||
didClickUserAvatar:(TLUser *)user;
|
||||
|
||||
/**
|
||||
* Message点击事件
|
||||
*/
|
||||
- (void)chatMessageDisplayView:(TLChatMessageDisplayView *)chatTVC
|
||||
didClickMessage:(TLMessage *)message;
|
||||
|
||||
/**
|
||||
* Message双击事件
|
||||
*/
|
||||
- (void)chatMessageDisplayView:(TLChatMessageDisplayView *)chatTVC
|
||||
didDoubleClickMessage:(TLMessage *)message;
|
||||
|
||||
@end
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// TLEmojiBaseCell.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/9.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TLExpressionModel.h"
|
||||
|
||||
@protocol TLEmojiCellProtocol <NSObject>
|
||||
|
||||
- (CGRect)displayBaseRect;
|
||||
|
||||
@end
|
||||
|
||||
@interface TLEmojiBaseCell : UICollectionViewCell <TLEmojiCellProtocol>
|
||||
|
||||
@property (nonatomic, strong) TLExpressionModel *emojiItem;
|
||||
|
||||
@property (nonatomic, strong) UIImageView *bgView;
|
||||
|
||||
/**
|
||||
* 选中时的背景图片,默认nil
|
||||
*/
|
||||
@property (nonatomic, strong) UIImage *highlightImage;
|
||||
|
||||
@property (nonatomic, assign) BOOL showHighlightImage;
|
||||
|
||||
@end
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// TLEmojiBaseCell.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/9.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLEmojiBaseCell.h"
|
||||
|
||||
@implementation TLEmojiBaseCell
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self.contentView addSubview:self.bgView];
|
||||
[self.bgView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.mas_equalTo(self.contentView);
|
||||
}];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CGRect)displayBaseRect
|
||||
{
|
||||
return self.frame;
|
||||
}
|
||||
|
||||
- (void)setShowHighlightImage:(BOOL)showHighlightImage
|
||||
{
|
||||
if (showHighlightImage) {
|
||||
[self.bgView setImage:self.highlightImage];
|
||||
}
|
||||
else {
|
||||
[self.bgView setImage:nil];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Getter -
|
||||
- (UIImageView *)bgView
|
||||
{
|
||||
if (_bgView == nil) {
|
||||
_bgView = [[UIImageView alloc] init];
|
||||
[_bgView.layer setMasksToBounds:YES];
|
||||
[_bgView.layer setCornerRadius:5.0f];
|
||||
}
|
||||
return _bgView;
|
||||
}
|
||||
|
||||
@end
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// TLEmojiFaceItemCell.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/9.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLEmojiBaseCell.h"
|
||||
|
||||
@interface TLEmojiFaceItemCell : TLEmojiBaseCell
|
||||
|
||||
@end
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
|
||||
//
|
||||
// TLEmojiFaceItemCell.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/9.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLEmojiFaceItemCell.h"
|
||||
|
||||
@interface TLEmojiFaceItemCell ()
|
||||
|
||||
@property (nonatomic, strong) UIImageView *imageView;
|
||||
|
||||
@property (nonatomic, strong) UILabel *label;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLEmojiFaceItemCell
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self.contentView addSubview:self.imageView];
|
||||
[self.imageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.center.mas_equalTo(self);
|
||||
make.size.mas_equalTo(CGSizeMake(32, 32));
|
||||
}];
|
||||
[self.contentView addSubview:self.label];
|
||||
[self.label mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.mas_equalTo(self.imageView);
|
||||
}];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setEmojiItem:(TLExpressionModel *)emojiItem
|
||||
{
|
||||
[super setEmojiItem:emojiItem];
|
||||
if ([emojiItem.eId isEqualToString:@"-1"]) {
|
||||
[self.imageView setHidden:NO];
|
||||
[self.label setHidden:YES];
|
||||
[self.imageView setImage:[UIImage imageNamed:@"emojiKB_emoji_delete"]];
|
||||
}
|
||||
else {
|
||||
if (emojiItem.type == TLEmojiTypeFace) {
|
||||
[self.imageView setHidden:NO];
|
||||
[self.label setHidden:YES];
|
||||
[self.imageView setImage:emojiItem.name == nil ? nil : [UIImage imageNamed:emojiItem.name]];
|
||||
}
|
||||
else {
|
||||
[self.imageView setHidden:YES];
|
||||
[self.label setHidden:NO];
|
||||
[self.label setText:emojiItem.name];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - # Getter
|
||||
- (UIImageView *)imageView
|
||||
{
|
||||
if (_imageView == nil) {
|
||||
_imageView = [[UIImageView alloc] init];
|
||||
}
|
||||
return _imageView;
|
||||
}
|
||||
|
||||
- (UILabel *)label
|
||||
{
|
||||
if (_label == nil) {
|
||||
_label = [[UILabel alloc] init];
|
||||
[_label setFont:[UIFont systemFontOfSize:28.0f]];
|
||||
[_label setTextAlignment:NSTextAlignmentCenter];
|
||||
}
|
||||
return _label;
|
||||
}
|
||||
|
||||
@end
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// TLEmojiImageItemCell.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/20.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLEmojiBaseCell.h"
|
||||
|
||||
@interface TLEmojiImageItemCell : TLEmojiBaseCell
|
||||
|
||||
|
||||
@end
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// TLEmojiImageItemCell.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/20.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLEmojiImageItemCell.h"
|
||||
|
||||
@interface TLEmojiImageItemCell ()
|
||||
|
||||
@property (nonatomic, strong) UIImageView *imageView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLEmojiImageItemCell
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self.contentView addSubview:self.imageView];
|
||||
[self setHighlightImage:[UIImage imageNamed:@"emoji_hl_background"]];
|
||||
[self p_addMasonry];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CGRect)displayBaseRect
|
||||
{
|
||||
CGRect rect = self.imageView.frame;
|
||||
rect.origin.x += self.x;
|
||||
rect.origin.y += self.y;
|
||||
return rect;
|
||||
}
|
||||
|
||||
- (void)setEmojiItem:(TLExpressionModel *)emojiItem
|
||||
{
|
||||
[super setEmojiItem:emojiItem];
|
||||
[self.imageView setImage:emojiItem.path == nil ? nil : [UIImage imageNamed:emojiItem.path]];
|
||||
}
|
||||
|
||||
#pragma mark - Private Methods -
|
||||
- (void)p_addMasonry
|
||||
{
|
||||
[self.imageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.center.mas_equalTo(self.contentView);
|
||||
make.size.mas_equalTo(CGSizeMake(52, 52));
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Getter -
|
||||
- (UIImageView *)imageView
|
||||
{
|
||||
if (_imageView == nil) {
|
||||
_imageView = [[UIImageView alloc] init];
|
||||
}
|
||||
return _imageView;
|
||||
}
|
||||
|
||||
@end
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// TLEmojiImageTitleItemCell.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/21.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLEmojiBaseCell.h"
|
||||
|
||||
@interface TLEmojiImageTitleItemCell : TLEmojiBaseCell
|
||||
|
||||
|
||||
@end
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// TLEmojiImageTitleItemCell.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/21.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLEmojiImageTitleItemCell.h"
|
||||
#import "UIImage+Color.h"
|
||||
|
||||
@interface TLEmojiImageTitleItemCell ()
|
||||
|
||||
@property (nonatomic, strong) UIImageView *imageView;
|
||||
|
||||
@property (nonatomic, strong) UILabel *label;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLEmojiImageTitleItemCell
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self setHighlightImage:[UIImage imageNamed:@"emoji_hl_background"]];
|
||||
[self.contentView addSubview:self.imageView];
|
||||
[self.contentView addSubview:self.label];
|
||||
[self p_addMasonry];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setEmojiItem:(TLExpressionModel *)emojiItem
|
||||
{
|
||||
[super setEmojiItem:emojiItem];
|
||||
[self.imageView setImage:emojiItem.path == nil ? nil : [UIImage imageNamed:emojiItem.path]];
|
||||
[self.label setText:emojiItem.name];
|
||||
}
|
||||
|
||||
- (CGRect)displayBaseRect
|
||||
{
|
||||
CGRect rect = self.imageView.frame;
|
||||
rect.origin.x += self.x;
|
||||
rect.origin.y += self.y;
|
||||
return rect;
|
||||
}
|
||||
|
||||
#pragma mark - Private Methods -
|
||||
- (void)p_addMasonry
|
||||
{
|
||||
[self.bgView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.mas_equalTo(self.imageView).mas_offset(UIEdgeInsetsMake(-3, -3, -3, -3));
|
||||
}];
|
||||
[self.imageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(3);
|
||||
make.centerX.mas_equalTo(0);
|
||||
make.size.mas_equalTo(CGSizeMake(50, 50));
|
||||
}];
|
||||
[self.label mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.mas_equalTo(0);
|
||||
make.width.mas_lessThanOrEqualTo(self).mas_offset(-8);
|
||||
make.top.mas_equalTo(self.imageView.mas_bottom).mas_offset(4);
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Getter -
|
||||
- (UIImageView *)imageView
|
||||
{
|
||||
if (_imageView == nil) {
|
||||
_imageView = [[UIImageView alloc] init];
|
||||
}
|
||||
return _imageView;
|
||||
}
|
||||
|
||||
- (UILabel *)label
|
||||
{
|
||||
if (_label == nil) {
|
||||
_label = [[UILabel alloc] init];
|
||||
[_label setFont:[UIFont systemFontOfSize:12.0f]];
|
||||
[_label setTextColor:[UIColor grayColor]];
|
||||
[_label setTextAlignment:NSTextAlignmentCenter];
|
||||
}
|
||||
return _label;
|
||||
}
|
||||
|
||||
@end
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// TLEmojiGroupDisplayView+CollectionView.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/9/27.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLEmojiGroupDisplayView.h"
|
||||
|
||||
@interface TLEmojiGroupDisplayView (CollectionView) <UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>
|
||||
|
||||
- (void)registerCellClass;
|
||||
|
||||
|
||||
- (NSUInteger)transformModelByRowCount:(NSInteger)rowCount colCount:(NSInteger)colCount andIndex:(NSInteger)index;
|
||||
|
||||
@end
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
//
|
||||
// TLEmojiGroupDisplayView+CollectionView.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/9/27.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLEmojiGroupDisplayView+CollectionView.h"
|
||||
#import "TLEmojiFaceItemCell.h"
|
||||
#import "TLEmojiImageItemCell.h"
|
||||
#import "TLEmojiImageTitleItemCell.h"
|
||||
|
||||
@implementation TLEmojiGroupDisplayView (CollectionView)
|
||||
|
||||
- (void)registerCellClass
|
||||
{
|
||||
[self.collectionView registerClass:[TLEmojiFaceItemCell class] forCellWithReuseIdentifier:@"TLEmojiFaceItemCell"];
|
||||
[self.collectionView registerClass:[TLEmojiImageItemCell class] forCellWithReuseIdentifier:@"TLEmojiImageItemCell"];
|
||||
[self.collectionView registerClass:[TLEmojiImageTitleItemCell class] forCellWithReuseIdentifier:@"TLEmojiImageTitleItemCell"];
|
||||
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"UICollectionViewCell"];
|
||||
}
|
||||
|
||||
- (NSUInteger)transformModelByRowCount:(NSInteger)rowCount colCount:(NSInteger)colCount andIndex:(NSInteger)index
|
||||
{
|
||||
NSUInteger x = index / rowCount;
|
||||
NSUInteger y = index % rowCount;
|
||||
return colCount * y + x;
|
||||
}
|
||||
|
||||
#pragma mark - # Delegate
|
||||
//MARK: UICollectionViewDelegate
|
||||
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
|
||||
{
|
||||
return self.displayData.count;
|
||||
}
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
|
||||
{
|
||||
TLEmojiGroupDisplayModel *group = self.displayData[section];
|
||||
return group.pageItemCount;
|
||||
}
|
||||
|
||||
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
TLEmojiGroupDisplayModel *group = self.displayData[indexPath.section];
|
||||
NSInteger index = [self transformModelByRowCount:group.rowNumber colCount:group.colNumber andIndex:indexPath.row];
|
||||
TLExpressionModel *emoji = [group objectAtIndex:index];
|
||||
TLEmojiBaseCell *cell;
|
||||
if (group.type == TLEmojiTypeEmoji || group.type == TLEmojiTypeFace) {
|
||||
cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TLEmojiFaceItemCell" forIndexPath:indexPath];
|
||||
}
|
||||
else if (group.type == TLEmojiTypeImageWithTitle) {
|
||||
cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TLEmojiImageTitleItemCell" forIndexPath:indexPath];
|
||||
}
|
||||
else {
|
||||
cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TLEmojiImageItemCell" forIndexPath:indexPath];
|
||||
}
|
||||
[cell setEmojiItem:emoji];
|
||||
return cell;
|
||||
}
|
||||
|
||||
//MARK: UICollectionViewDelegate
|
||||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
TLEmojiGroupDisplayModel *group = self.displayData[indexPath.section];
|
||||
NSInteger index = [self transformModelByRowCount:group.rowNumber colCount:group.colNumber andIndex:indexPath.row];
|
||||
TLExpressionModel *emoji = [group objectAtIndex:index];
|
||||
if (emoji) {
|
||||
if ([emoji.eId isEqualToString:@"-1"]) {
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(emojiGroupDisplayViewDeleteButtonPressed:)]) {
|
||||
[self.delegate emojiGroupDisplayViewDeleteButtonPressed:self];
|
||||
}
|
||||
}
|
||||
else if (self.delegate && [self.delegate respondsToSelector:@selector(emojiGroupDisplayView:didClickedEmoji:)]) {
|
||||
//FIXME: 表情类型
|
||||
emoji.type = group.type;
|
||||
[self.delegate emojiGroupDisplayView:self didClickedEmoji:emoji];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
TLEmojiGroupDisplayModel *group = self.displayData[indexPath.section];
|
||||
return group.cellSize;
|
||||
}
|
||||
|
||||
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
|
||||
{
|
||||
TLEmojiGroupDisplayModel *group = self.displayData[section];
|
||||
return group.sectionInsets;
|
||||
}
|
||||
|
||||
//MARK: UIScrollViewDelegate
|
||||
static float lastX = 0;
|
||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
|
||||
{
|
||||
NSInteger page = (scrollView.contentOffset.x + 2.0) / scrollView.width;
|
||||
if (scrollView.contentOffset.x < lastX) { // 右滑坐标修复
|
||||
page += (scrollView.contentOffset.x - scrollView.width * page > 3.0) ? 1 : 0;
|
||||
}
|
||||
lastX = scrollView.contentOffset.x;
|
||||
|
||||
if (self.curPageIndex != page) {
|
||||
self.curPageIndex = page;
|
||||
if (page >= 0 && page < self.displayData.count && self.delegate && [self.delegate respondsToSelector:@selector(emojiGroupDisplayView:didScrollToPageIndex:forGroupIndex:)]) {
|
||||
TLEmojiGroupDisplayModel *group = self.displayData[page];
|
||||
[self.delegate emojiGroupDisplayView:self didScrollToPageIndex:group.pageIndex forGroupIndex:group.emojiGroupIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// TLEmojiGroupDisplayView+Gesture.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/9/28.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLEmojiGroupDisplayView.h"
|
||||
|
||||
@interface TLEmojiGroupDisplayView (Gesture)
|
||||
|
||||
- (void)addGusture;
|
||||
|
||||
@end
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
//
|
||||
// TLEmojiGroupDisplayView+Gesture.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/9/28.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLEmojiGroupDisplayView+Gesture.h"
|
||||
#import "TLEmojiGroupDisplayView+CollectionView.h"
|
||||
#import "TLEmojiBaseCell.h"
|
||||
|
||||
@implementation TLEmojiGroupDisplayView (Gesture)
|
||||
|
||||
#pragma mark - # Public Methods
|
||||
- (void)addGusture
|
||||
{
|
||||
UILongPressGestureRecognizer *longPressGR = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressAction:)];
|
||||
[self.collectionView addGestureRecognizer:longPressGR];
|
||||
}
|
||||
|
||||
#pragma mark - # Event Response
|
||||
static UICollectionViewCell *lastCell;
|
||||
- (void)longPressAction:(UILongPressGestureRecognizer *)sender
|
||||
{
|
||||
TLEmojiGroupDisplayModel *curGroup = [self.displayData objectAtIndex:self.curPageIndex];
|
||||
CGPoint point = [sender locationInView:self.collectionView];
|
||||
if (sender.state == UIGestureRecognizerStateEnded || sender.state == UIGestureRecognizerStateCancelled) { // 长按停止
|
||||
[self p_cancelLongPressEmoji];
|
||||
lastCell = nil;
|
||||
}
|
||||
else if (sender.state == UIGestureRecognizerStateBegan) {
|
||||
NSArray *visableCells = self.collectionView.visibleCells;
|
||||
for (TLEmojiBaseCell *cell in visableCells) {
|
||||
if (cell.x <= point.x && cell.y <= point.y && cell.x + curGroup.cellSize.width >= point.x && cell.y + curGroup.cellSize.height >= point.y) {
|
||||
NSIndexPath *indexPath = [self.collectionView indexPathForCell:cell];
|
||||
NSInteger index = [self transformModelByRowCount:curGroup.rowNumber colCount:curGroup.colNumber andIndex:indexPath.row]; // 矩阵坐标转置
|
||||
TLExpressionModel *emoji = [curGroup objectAtIndex:index];
|
||||
if (emoji) {
|
||||
if ((emoji.type == TLEmojiTypeEmoji || emoji.type == TLEmojiTypeFace) && [emoji.eId isEqualToString:@"-1"]) { // 删除
|
||||
|
||||
}
|
||||
else {
|
||||
CGRect rect = [cell displayBaseRect];
|
||||
rect.origin.x = rect.origin.x - self.width * (int)(rect.origin.x / self.width);
|
||||
[self p_startLongPressEmoji:emoji atRect:rect];
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
lastCell = nil;
|
||||
}
|
||||
else {
|
||||
NSArray *visableCells = self.collectionView.visibleCells;
|
||||
for (TLEmojiBaseCell *cell in visableCells) {
|
||||
if (cell.x <= point.x && cell.y <= point.y && cell.x + curGroup.cellSize.width >= point.x && cell.y + curGroup.cellSize.height >= point.y) {
|
||||
if (cell == lastCell) {
|
||||
return;
|
||||
}
|
||||
NSIndexPath *indexPath = [self.collectionView indexPathForCell:cell];
|
||||
NSInteger index = [self transformModelByRowCount:curGroup.rowNumber colCount:curGroup.colNumber andIndex:indexPath.row]; // 矩阵坐标转置
|
||||
TLExpressionModel *emoji = [curGroup objectAtIndex:index];
|
||||
if (emoji) {
|
||||
if ((emoji.type == TLEmojiTypeEmoji || emoji.type == TLEmojiTypeFace) && [emoji.eId isEqualToString:@"-1"]) { // 删除
|
||||
[self p_cancelLongPressEmoji];
|
||||
}
|
||||
else {
|
||||
CGRect rect = [cell displayBaseRect];
|
||||
rect.origin.x = rect.origin.x - self.width * (int)(rect.origin.x / self.width);
|
||||
[self p_startLongPressEmoji:emoji atRect:rect];
|
||||
}
|
||||
}
|
||||
else { // 空白cell
|
||||
[self p_cancelLongPressEmoji];
|
||||
}
|
||||
lastCell = cell;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 超出界限
|
||||
if (lastCell) {
|
||||
[self p_cancelLongPressEmoji];
|
||||
lastCell = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - # Private Methods
|
||||
static TLExpressionModel *lastEmoji;
|
||||
- (void)p_startLongPressEmoji:(TLExpressionModel *)emoji atRect:(CGRect)rect
|
||||
{
|
||||
if (emoji != lastEmoji) {
|
||||
lastEmoji = emoji;
|
||||
TLEmojiGroupDisplayModel *curGroup = [self.displayData objectAtIndex:self.curPageIndex];
|
||||
emoji.type = curGroup.type;
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(emojiGroupDisplayView:didLongPressEmoji:atRect:)]) {
|
||||
[self.delegate emojiGroupDisplayView:self didLongPressEmoji:emoji atRect:rect];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)p_cancelLongPressEmoji
|
||||
{
|
||||
if (lastEmoji) {
|
||||
lastEmoji = nil;
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(emojiGroupDisplayViewDidStopLongPressEmoji:)]) { // 停止长按表情
|
||||
[self.delegate emojiGroupDisplayViewDidStopLongPressEmoji:self];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// TLEmojiGroupDisplayView.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/9/27.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TLEmojiGroupDisplayViewDelegate.h"
|
||||
#import "TLEmojiGroupDisplayModel.h"
|
||||
|
||||
@interface TLEmojiGroupDisplayView : UIView
|
||||
|
||||
@property (nonatomic, weak) id<TLEmojiGroupDisplayViewDelegate> delegate;
|
||||
|
||||
@property (nonatomic, weak) NSMutableArray *data;
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray *displayData;
|
||||
|
||||
@property (nonatomic, strong) UICollectionView *collectionView;
|
||||
|
||||
@property (nonatomic, assign) NSInteger curPageIndex;
|
||||
|
||||
- (void)scrollToEmojiGroupAtIndex:(NSInteger)index;
|
||||
|
||||
@end
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
//
|
||||
// TLEmojiGroupDisplayView.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/9/27.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLEmojiGroupDisplayView.h"
|
||||
#import "TLEmojiGroupDisplayView+CollectionView.h"
|
||||
#import "TLEmojiGroupDisplayView+Gesture.h"
|
||||
#import "TLExpressionGroupModel+TLEmojiKB.h"
|
||||
|
||||
@implementation TLEmojiGroupDisplayView
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self addSubview:self.collectionView];
|
||||
[self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.mas_equalTo(0);
|
||||
}];
|
||||
|
||||
[self registerCellClass];
|
||||
[self addGusture];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setData:(NSMutableArray *)data
|
||||
{
|
||||
if (data && _data && [_data isEqualToArray:data]) {
|
||||
return;
|
||||
}
|
||||
_data = data;
|
||||
|
||||
self.height = HEIGHT_CHAT_KEYBOARD - 57;
|
||||
self.width = SCREEN_WIDTH;
|
||||
|
||||
NSMutableArray *displayData = [[NSMutableArray alloc] init];
|
||||
for (NSInteger emojiGroupIndex = 0; emojiGroupIndex < data.count; emojiGroupIndex++) {
|
||||
TLExpressionGroupModel *group = data[emojiGroupIndex];
|
||||
if (group.count > 0) { // 已下载的表情包
|
||||
NSInteger cellWidth, cellHeight;
|
||||
CGFloat spaceX, spaceYTop, spaceYBottom;
|
||||
cellWidth = ((self.width - 20) / group.colNumber);
|
||||
spaceX = (self.width - cellWidth * group.colNumber) / 2.0;
|
||||
if (group.type == TLEmojiTypeEmoji || group.type == TLEmojiTypeFace) {
|
||||
cellHeight = (self.height - 15) / group.rowNumber;
|
||||
spaceYTop = 10;
|
||||
}
|
||||
else if (group.type == TLEmojiTypeImageWithTitle) {
|
||||
cellHeight = (self.height - 10) / group.rowNumber;
|
||||
spaceYTop = 10;
|
||||
}
|
||||
else {
|
||||
cellHeight = (self.height - 40) / group.rowNumber;
|
||||
spaceYTop = 20;
|
||||
}
|
||||
spaceYBottom = (self.height - cellHeight * group.rowNumber) - spaceYTop;
|
||||
for (NSInteger pageIndex = 0; pageIndex < group.pageNumber; pageIndex++) {
|
||||
TLEmojiGroupDisplayModel *model = [[TLEmojiGroupDisplayModel alloc] initWithEmojiGroup:group pageNumber:pageIndex andCount:group.pageItemCount];
|
||||
if (model.type == TLEmojiTypeEmoji || group.type == TLEmojiTypeFace) { // 为默认表情包添加删除按钮
|
||||
TLExpressionModel *emoji = [[TLExpressionModel alloc] init];
|
||||
emoji.eId = @"-1";
|
||||
emoji.name = @"del";
|
||||
[model addEmoji:emoji];
|
||||
model.pageItemCount ++;
|
||||
}
|
||||
model.emojiGroupIndex = emojiGroupIndex;
|
||||
model.pageIndex = pageIndex;
|
||||
model.cellSize = CGSizeMake(cellWidth, cellHeight);
|
||||
model.sectionInsets = UIEdgeInsetsMake(spaceYTop, spaceX, spaceYBottom, spaceX);
|
||||
[displayData addObject:model];
|
||||
}
|
||||
}
|
||||
}
|
||||
self.displayData = displayData;
|
||||
[self.collectionView reloadData];
|
||||
if (self.displayData.count > 0 && self.delegate && [self.delegate respondsToSelector:@selector(emojiGroupDisplayView:didScrollToPageIndex:forGroupIndex:)]) {
|
||||
TLEmojiGroupDisplayModel *group = self.displayData[0];
|
||||
[self.collectionView setContentOffset:CGPointZero];
|
||||
[self.delegate emojiGroupDisplayView:self didScrollToPageIndex:0 forGroupIndex:group.emojiGroupIndex];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollToEmojiGroupAtIndex:(NSInteger)index
|
||||
{
|
||||
if (index > self.data.count) {
|
||||
return;
|
||||
}
|
||||
_curPageIndex = index;
|
||||
NSInteger page = 0;
|
||||
for (int i = 0; i < index; i ++) {
|
||||
TLExpressionGroupModel *group = self.data[i];
|
||||
page += group.pageNumber;
|
||||
}
|
||||
[self.collectionView setContentOffset:CGPointMake(page * self.collectionView.width, 0)];
|
||||
if (self.displayData.count > page) {
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(emojiGroupDisplayView:didScrollToPageIndex:forGroupIndex:)]) {
|
||||
TLEmojiGroupDisplayModel *group = self.displayData[page];
|
||||
[self.delegate emojiGroupDisplayView:self didScrollToPageIndex:0 forGroupIndex:group.emojiGroupIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - # Getter
|
||||
- (UICollectionView *)collectionView
|
||||
{
|
||||
if (_collectionView == nil) {
|
||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||
[layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
|
||||
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||
[_collectionView setBackgroundColor:[UIColor clearColor]];
|
||||
[_collectionView setPagingEnabled:YES];
|
||||
[_collectionView setDataSource:self];
|
||||
[_collectionView setDelegate:self];
|
||||
[_collectionView setShowsHorizontalScrollIndicator:NO];
|
||||
[_collectionView setShowsHorizontalScrollIndicator:NO];
|
||||
[_collectionView setScrollsToTop:NO];
|
||||
}
|
||||
return _collectionView;
|
||||
}
|
||||
|
||||
@end
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// TLEmojiGroupDisplayViewDelegate.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/9/27.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class TLExpressionModel;
|
||||
@class TLEmojiGroupDisplayView;
|
||||
@protocol TLEmojiGroupDisplayViewDelegate <NSObject>
|
||||
|
||||
/**
|
||||
* 发送按钮点击事件
|
||||
*/
|
||||
- (void)emojiGroupDisplayViewDeleteButtonPressed:(TLEmojiGroupDisplayView *)displayView;
|
||||
|
||||
/**
|
||||
* 选中表情
|
||||
*/
|
||||
- (void)emojiGroupDisplayView:(TLEmojiGroupDisplayView *)displayView didClickedEmoji:(TLExpressionModel *)emoji;
|
||||
|
||||
/**
|
||||
* 翻页
|
||||
*/
|
||||
- (void)emojiGroupDisplayView:(TLEmojiGroupDisplayView *)displayView didScrollToPageIndex:(NSInteger)pageIndex forGroupIndex:(NSInteger)groupIndex;
|
||||
|
||||
/**
|
||||
* 表情长按
|
||||
*/
|
||||
- (void)emojiGroupDisplayView:(TLEmojiGroupDisplayView *)displayView didLongPressEmoji:(TLExpressionModel *)emoji atRect:(CGRect)rect;
|
||||
|
||||
/**
|
||||
* 停止表情长按
|
||||
*/
|
||||
- (void)emojiGroupDisplayViewDidStopLongPressEmoji:(TLEmojiGroupDisplayView *)displayView;
|
||||
|
||||
@end
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// TLEmojiGroupCell.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/19.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TLExpressionGroupModel.h"
|
||||
|
||||
@interface TLEmojiGroupCell : UICollectionViewCell
|
||||
|
||||
@property (nonatomic, strong) TLExpressionGroupModel *emojiGroup;
|
||||
|
||||
@end
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// TLEmojiGroupCell.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/19.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLEmojiGroupCell.h"
|
||||
|
||||
@interface TLEmojiGroupCell ()
|
||||
|
||||
@property (nonatomic, strong) UIImageView *groupIconView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLEmojiGroupCell
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self setBackgroundColor:[UIColor clearColor]];
|
||||
UIView *selectedView = [[UIView alloc] init];
|
||||
[selectedView setBackgroundColor:[UIColor colorGrayForChatBar]];
|
||||
[self setSelectedBackgroundView:selectedView];
|
||||
|
||||
[self.contentView addSubview:self.groupIconView];
|
||||
[self p_addMasonry];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setEmojiGroup:(TLExpressionGroupModel *)emojiGroup
|
||||
{
|
||||
_emojiGroup = emojiGroup;
|
||||
[self.groupIconView setImage:[UIImage imageNamed:emojiGroup.iconPath]];
|
||||
}
|
||||
|
||||
#pragma mark - # Private Methods
|
||||
- (void)p_addMasonry
|
||||
{
|
||||
[self.groupIconView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.center.mas_equalTo(self.contentView);
|
||||
make.width.and.height.mas_lessThanOrEqualTo(30);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)rect
|
||||
{
|
||||
[super drawRect:rect];
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
CGContextSetLineWidth(context, 0.5);
|
||||
CGContextSetStrokeColorWithColor(context, [UIColor colorGrayLine].CGColor);
|
||||
CGContextBeginPath(context);
|
||||
CGContextMoveToPoint(context, self.width - 0.5, 5);
|
||||
CGContextAddLineToPoint(context, self.width - 0.5, self.height - 5);
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
#pragma mark - Getter -
|
||||
- (UIImageView *)groupIconView
|
||||
{
|
||||
if (_groupIconView == nil) {
|
||||
_groupIconView = [[UIImageView alloc] init];
|
||||
}
|
||||
return _groupIconView;
|
||||
}
|
||||
|
||||
@end
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// TLEmojiGroupControl.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/19.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TLExpressionGroupModel.h"
|
||||
|
||||
typedef NS_ENUM(NSInteger, TLGroupControlSendButtonStatus) {
|
||||
TLGroupControlSendButtonStatusGray,
|
||||
TLGroupControlSendButtonStatusBlue,
|
||||
TLGroupControlSendButtonStatusNone,
|
||||
};
|
||||
|
||||
@class TLEmojiGroupControl;
|
||||
@protocol TLEmojiGroupControlDelegate <NSObject>
|
||||
|
||||
- (void)emojiGroupControl:(TLEmojiGroupControl*)emojiGroupControl didSelectedGroup:(TLExpressionGroupModel *)group;
|
||||
|
||||
- (void)emojiGroupControlEditButtonDown:(TLEmojiGroupControl *)emojiGroupControl;
|
||||
|
||||
- (void)emojiGroupControlEditMyEmojiButtonDown:(TLEmojiGroupControl *)emojiGroupControl;
|
||||
|
||||
- (void)emojiGroupControlSendButtonDown:(TLEmojiGroupControl *)emojiGroupControl;
|
||||
|
||||
@end
|
||||
|
||||
@interface TLEmojiGroupControl : UIView
|
||||
|
||||
@property (nonatomic, assign) TLGroupControlSendButtonStatus sendButtonStatus;
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray *emojiGroupData;
|
||||
|
||||
@property (nonatomic, assign) id<TLEmojiGroupControlDelegate>delegate;
|
||||
|
||||
- (void)selectEmojiGroupAtIndex:(NSInteger)index;
|
||||
|
||||
@end
|
||||
+278
@@ -0,0 +1,278 @@
|
||||
//
|
||||
// TLEmojiGroupControl.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/19.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLEmojiGroupControl.h"
|
||||
#import "TLEmojiGroupCell.h"
|
||||
|
||||
#define WIDTH_EMOJIGROUP_CELL 46
|
||||
#define WIDTH_SENDBUTTON 60
|
||||
|
||||
@interface TLEmojiGroupControl () <UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>
|
||||
|
||||
@property (nonatomic, strong) NSIndexPath *curIndexPath;
|
||||
|
||||
@property (nonatomic, strong) UIButton *addButton;
|
||||
|
||||
@property (nonatomic, strong) UICollectionView *collectionView;
|
||||
|
||||
@property (nonatomic, strong) UIButton *sendButton;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLEmojiGroupControl
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
[self setBackgroundColor:[UIColor whiteColor]];
|
||||
[self addSubview:self.addButton];
|
||||
[self addSubview:self.collectionView];
|
||||
[self addSubview:self.sendButton];
|
||||
[self p_addMasonry];
|
||||
|
||||
[self.collectionView registerClass:[TLEmojiGroupCell class] forCellWithReuseIdentifier:@"TLEmojiGroupCell"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setSendButtonStatus:(TLGroupControlSendButtonStatus)sendButtonStatus
|
||||
{
|
||||
if (_sendButtonStatus != sendButtonStatus) {
|
||||
if (_sendButtonStatus == TLGroupControlSendButtonStatusNone) {
|
||||
[self.sendButton mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.mas_equalTo(self);
|
||||
}];
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
[self layoutIfNeeded];
|
||||
} completion:^(BOOL finished) {
|
||||
[self.collectionView reloadData];
|
||||
[self.collectionView selectItemAtIndexPath:self.curIndexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone];
|
||||
}];
|
||||
if (sendButtonStatus == TLGroupControlSendButtonStatusBlue) {
|
||||
[_sendButton setBackgroundImage:[UIImage imageNamed:@"emojiKB_sendBtn_blue"] forState:UIControlStateNormal];
|
||||
[_sendButton setBackgroundImage:[UIImage imageNamed:@"emojiKB_sendBtn_blueHL"] forState:UIControlStateHighlighted];
|
||||
[_sendButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
||||
}
|
||||
else if (sendButtonStatus == TLGroupControlSendButtonStatusGray) {
|
||||
[_sendButton setBackgroundImage:[UIImage imageNamed:@"emojiKB_sendBtn_gray"] forState:UIControlStateNormal];
|
||||
[_sendButton setBackgroundImage:[UIImage imageNamed:@"emojiKB_sendBtn_gray"] forState:UIControlStateHighlighted];
|
||||
[_sendButton setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
|
||||
}
|
||||
}
|
||||
else if (sendButtonStatus == TLGroupControlSendButtonStatusNone) {
|
||||
[self.sendButton mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.mas_equalTo(self).mas_offset(WIDTH_SENDBUTTON);
|
||||
}];
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
[self layoutIfNeeded];
|
||||
} completion:^(BOOL finished) {
|
||||
[self.collectionView reloadData];
|
||||
[self.collectionView selectItemAtIndexPath:self.curIndexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone];
|
||||
}];
|
||||
}
|
||||
_sendButtonStatus = sendButtonStatus;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setEmojiGroupData:(NSMutableArray *)emojiGroupData
|
||||
{
|
||||
if (_emojiGroupData == emojiGroupData || [_emojiGroupData isEqualToArray:emojiGroupData]) {
|
||||
return;
|
||||
}
|
||||
_emojiGroupData = emojiGroupData;
|
||||
[self.collectionView reloadData];
|
||||
if (emojiGroupData && emojiGroupData.count > 0) {
|
||||
[self setCurIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)selectEmojiGroupAtIndex:(NSInteger)index
|
||||
{
|
||||
if (index < self.emojiGroupData.count) {
|
||||
_curIndexPath = [NSIndexPath indexPathForRow:index inSection:0];
|
||||
[self.collectionView selectItemAtIndexPath:_curIndexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone];
|
||||
CGFloat width = WIDTH_EMOJIGROUP_CELL;
|
||||
CGFloat x = width * index;
|
||||
if (x < self.collectionView.contentOffset.x) {
|
||||
[self.collectionView setContentOffset:CGPointMake(x, 0) animated:YES];
|
||||
}
|
||||
else if (x + width > self.collectionView.contentOffset.x + self.collectionView.width) {
|
||||
[self.collectionView setContentOffset:CGPointMake(x + width - self.collectionView.width, 0) animated:YES];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setCurIndexPath:(NSIndexPath *)curIndexPath
|
||||
{
|
||||
if (curIndexPath.row < self.emojiGroupData.count) {
|
||||
[self.collectionView scrollToItemAtIndexPath:curIndexPath atScrollPosition:UICollectionViewScrollPositionNone animated:YES];
|
||||
[self.collectionView selectItemAtIndexPath:curIndexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone];
|
||||
if (_curIndexPath && _curIndexPath.section == curIndexPath.section && _curIndexPath.row == curIndexPath.row) {
|
||||
return;
|
||||
}
|
||||
|
||||
CGFloat width = WIDTH_EMOJIGROUP_CELL;
|
||||
CGFloat x = width * curIndexPath.row;
|
||||
if (x < self.collectionView.contentOffset.x) {
|
||||
[self.collectionView setContentOffset:CGPointMake(x, 0) animated:YES];
|
||||
}
|
||||
else if (x + width > self.collectionView.contentOffset.x + self.collectionView.width) {
|
||||
[self.collectionView setContentOffset:CGPointMake(x + width - self.collectionView.width, 0) animated:YES];
|
||||
}
|
||||
|
||||
_curIndexPath = curIndexPath;
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(emojiGroupControl:didSelectedGroup:)]) {
|
||||
TLExpressionGroupModel *group = [self.emojiGroupData objectAtIndex:curIndexPath.row];
|
||||
[_delegate emojiGroupControl:self didSelectedGroup:group];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - # Delegate
|
||||
//MARK: UICollectionViewDataSource
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
|
||||
{
|
||||
return self.emojiGroupData.count;
|
||||
}
|
||||
|
||||
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
TLEmojiGroupCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TLEmojiGroupCell" forIndexPath:indexPath];
|
||||
TLExpressionGroupModel *group = [self.emojiGroupData objectAtIndex:indexPath.row];
|
||||
[cell setEmojiGroup:group];
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
return CGSizeMake(WIDTH_EMOJIGROUP_CELL, self.height);
|
||||
}
|
||||
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section
|
||||
{
|
||||
if (section == self.emojiGroupData.count - 1) {
|
||||
return CGSizeMake(WIDTH_EMOJIGROUP_CELL * 2, self.height);
|
||||
}
|
||||
return CGSizeZero;
|
||||
}
|
||||
|
||||
|
||||
//MARK: UICollectionViewDelegate
|
||||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
TLExpressionGroupModel *group = [self.emojiGroupData objectAtIndex:indexPath.row];
|
||||
if (group.type == TLEmojiTypeOther) {
|
||||
//???: 存在冲突:用户选中cellA,再此方法中立马调用方法选中cellB时,所有cell都不会被选中
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self setCurIndexPath:_curIndexPath];
|
||||
});
|
||||
[self p_eidtMyEmojiButtonDown];
|
||||
}
|
||||
else {
|
||||
[self setCurIndexPath:indexPath];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - # Event Response
|
||||
- (void)emojiAddButtonDown
|
||||
{
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(emojiGroupControlEditButtonDown:)]) {
|
||||
[_delegate emojiGroupControlEditButtonDown:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sendButtonDown
|
||||
{
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(emojiGroupControlSendButtonDown:)]) {
|
||||
[_delegate emojiGroupControlSendButtonDown:self];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - # Private Methods
|
||||
- (void)p_addMasonry
|
||||
{
|
||||
[self.addButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.and.top.and.bottom.mas_equalTo(self);
|
||||
make.width.mas_equalTo(WIDTH_EMOJIGROUP_CELL);
|
||||
}];
|
||||
|
||||
[self.sendButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.and.bottom.and.right.mas_equalTo(self);
|
||||
make.width.mas_equalTo(WIDTH_SENDBUTTON);
|
||||
}];
|
||||
|
||||
[self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.and.bottom.mas_equalTo(self);
|
||||
make.left.mas_equalTo(self.addButton.mas_right);
|
||||
make.right.mas_equalTo(self.sendButton.mas_left);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)p_eidtMyEmojiButtonDown
|
||||
{
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(emojiGroupControlEditMyEmojiButtonDown:)]) {
|
||||
[_delegate emojiGroupControlEditMyEmojiButtonDown:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)rect
|
||||
{
|
||||
[super drawRect:rect];
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
CGContextSetLineWidth(context, 0.5);
|
||||
CGContextSetStrokeColorWithColor(context, [UIColor colorGrayLine].CGColor);
|
||||
CGContextBeginPath(context);
|
||||
CGContextMoveToPoint(context, WIDTH_EMOJIGROUP_CELL, 5);
|
||||
CGContextAddLineToPoint(context, WIDTH_EMOJIGROUP_CELL, self.height - 5);
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
#pragma mark - # Getter
|
||||
- (UIButton *)addButton
|
||||
{
|
||||
if (_addButton == nil) {
|
||||
_addButton = [[UIButton alloc] init];
|
||||
[_addButton setImage:[UIImage imageNamed:@"emojiKB_groupControl_add"] forState:UIControlStateNormal];
|
||||
[_addButton addTarget:self action:@selector(emojiAddButtonDown) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _addButton;
|
||||
}
|
||||
|
||||
- (UICollectionView *)collectionView
|
||||
{
|
||||
if (_collectionView == nil) {
|
||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||
[layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
|
||||
[layout setMinimumLineSpacing:0];
|
||||
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||
[_collectionView setBackgroundColor:[UIColor clearColor]];
|
||||
[_collectionView setDataSource:self];
|
||||
[_collectionView setDelegate:self];
|
||||
[_collectionView setShowsHorizontalScrollIndicator:NO];
|
||||
[_collectionView setShowsHorizontalScrollIndicator:NO];
|
||||
[_collectionView setScrollsToTop:NO];
|
||||
}
|
||||
return _collectionView;
|
||||
}
|
||||
|
||||
- (UIButton *)sendButton
|
||||
{
|
||||
if (_sendButton == nil) {
|
||||
_sendButton = [[UIButton alloc] init];
|
||||
[_sendButton.titleLabel setFont:[UIFont systemFontOfSize:15.0f]];
|
||||
[_sendButton setTitle:@" 发送" forState:UIControlStateNormal];
|
||||
[_sendButton setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
|
||||
[_sendButton setBackgroundColor:[UIColor clearColor]];
|
||||
[_sendButton setBackgroundImage:[UIImage imageNamed:@"emojiKB_sendBtn_gray"] forState:UIControlStateNormal];
|
||||
[_sendButton setBackgroundImage:[UIImage imageNamed:@"emojiKB_sendBtn_gray"] forState:UIControlStateHighlighted];
|
||||
[_sendButton addTarget:self action:@selector(sendButtonDown) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _sendButton;
|
||||
}
|
||||
|
||||
@end
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// TLEmojiGroupDisplayModel.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/9/27.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "TLExpressionGroupModel.h"
|
||||
|
||||
@interface TLEmojiGroupDisplayModel : NSObject
|
||||
|
||||
@property (nonatomic, assign) TLEmojiType type;
|
||||
|
||||
@property (nonatomic, strong) NSString *groupID;
|
||||
|
||||
@property (nonatomic, strong) NSString *groupName;
|
||||
|
||||
@property (nonatomic, strong) NSString *groupIconPath;
|
||||
|
||||
@property (nonatomic, assign) NSUInteger count;
|
||||
|
||||
@property (nonatomic, strong) NSArray *data;
|
||||
|
||||
#pragma mark - 标记
|
||||
|
||||
@property (nonatomic, assign) NSInteger emojiGroupIndex;
|
||||
|
||||
@property (nonatomic, assign) NSInteger pageIndex;
|
||||
|
||||
#pragma mark - 展示用
|
||||
|
||||
/// 每页个数
|
||||
@property (nonatomic, assign) NSUInteger pageItemCount;
|
||||
|
||||
/// 页数
|
||||
@property (nonatomic, assign) NSUInteger pageNumber;
|
||||
|
||||
/// 行数
|
||||
@property (nonatomic, assign) NSUInteger rowNumber;
|
||||
|
||||
/// 列数
|
||||
@property (nonatomic, assign) NSUInteger colNumber;
|
||||
|
||||
@property (nonatomic, assign) CGSize cellSize;
|
||||
|
||||
@property (nonatomic, assign) UIEdgeInsets sectionInsets;
|
||||
|
||||
|
||||
- (id)initWithEmojiGroup:(TLExpressionGroupModel *)emojiGroup pageNumber:(NSInteger)pageNumber andCount:(NSInteger)count;
|
||||
|
||||
- (id)objectAtIndex:(NSUInteger)index;
|
||||
|
||||
- (void)addEmoji:(TLExpressionModel *)emoji;
|
||||
|
||||
@end
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// TLEmojiGroupDisplayModel.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/9/27.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLEmojiGroupDisplayModel.h"
|
||||
#import "TLExpressionGroupModel+TLEmojiKB.h"
|
||||
|
||||
@implementation TLEmojiGroupDisplayModel
|
||||
- (id)initWithEmojiGroup:(TLExpressionGroupModel *)emojiGroup pageNumber:(NSInteger)pageNumber andCount:(NSInteger)count
|
||||
{
|
||||
if (self = [super init]) {
|
||||
self.groupID = emojiGroup.gId;
|
||||
self.groupName = emojiGroup.name;
|
||||
self.type = emojiGroup.type;
|
||||
|
||||
self.rowNumber = emojiGroup.rowNumber;
|
||||
self.colNumber = emojiGroup.colNumber;
|
||||
self.pageItemCount = emojiGroup.pageItemCount;
|
||||
|
||||
NSInteger start = pageNumber * count;
|
||||
if (emojiGroup.data.count > start) {
|
||||
NSInteger len = MIN(count, emojiGroup.count - start);
|
||||
self.data = [emojiGroup.data subarrayWithRange:NSMakeRange(pageNumber * count, len)];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)objectAtIndex:(NSUInteger)index
|
||||
{
|
||||
return index < self.data.count ? [self.data objectAtIndex:index] : nil;
|
||||
}
|
||||
|
||||
- (void)addEmoji:(TLExpressionModel *)emoji
|
||||
{
|
||||
NSMutableArray *emojis = [NSMutableArray arrayWithArray:self.data];
|
||||
[emojis addObject:emoji];
|
||||
self.data = emojis;
|
||||
}
|
||||
@end
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// TLEmojiKeyboardDelegate.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/20.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "TLExpressionModel.h"
|
||||
|
||||
@class TLEmojiKeyboard;
|
||||
@protocol TLEmojiKeyboardDelegate <NSObject>
|
||||
|
||||
- (BOOL)chatInputViewHasText;
|
||||
|
||||
@optional
|
||||
/**
|
||||
* 长按某个表情(展示)
|
||||
*/
|
||||
- (void)emojiKeyboard:(TLEmojiKeyboard *)emojiKB didTouchEmojiItem:(TLExpressionModel *)emoji atRect:(CGRect)rect;
|
||||
|
||||
/**
|
||||
* 取消长按某个表情(停止展示)
|
||||
*/
|
||||
- (void)emojiKeyboardCancelTouchEmojiItem:(TLEmojiKeyboard *)emojiKB;
|
||||
|
||||
/**
|
||||
* 点击事件 —— 选中某个表情
|
||||
*/
|
||||
- (void)emojiKeyboard:(TLEmojiKeyboard *)emojiKB didSelectedEmojiItem:(TLExpressionModel *)emoji;
|
||||
|
||||
/**
|
||||
* 点击事件 —— 表情发送按钮
|
||||
*/
|
||||
- (void)emojiKeyboardSendButtonDown;
|
||||
|
||||
/**
|
||||
* 点击事件 —— 删除按钮
|
||||
*/
|
||||
- (void)emojiKeyboardDeleteButtonDown;
|
||||
|
||||
/**
|
||||
* 点击事件 —— 表情编辑按钮
|
||||
*/
|
||||
- (void)emojiKeyboardEmojiEditButtonDown;
|
||||
|
||||
/**
|
||||
* 点击事件 —— 我的表情按钮
|
||||
*/
|
||||
- (void)emojiKeyboardMyEmojiEditButtonDown;
|
||||
|
||||
/**
|
||||
* 选中不同类型的表情组回调
|
||||
* 用于改变chatBar状态(个性表情组展示时textView不可用)
|
||||
*/
|
||||
- (void)emojiKeyboard:(TLEmojiKeyboard *)emojiKB selectedEmojiGroupType:(TLEmojiType)type;
|
||||
|
||||
@end
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// TLExpressionGroupModel+TLEmojiKB.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 2018/1/2.
|
||||
// Copyright © 2018年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLExpressionGroupModel.h"
|
||||
|
||||
@interface TLExpressionGroupModel (TLEmojiKB)
|
||||
|
||||
|
||||
/// 每页个数
|
||||
@property (nonatomic, assign, readonly) NSUInteger pageItemCount;
|
||||
|
||||
/// 页数
|
||||
@property (nonatomic, assign, readonly) NSUInteger pageNumber;
|
||||
|
||||
/// 行数
|
||||
@property (nonatomic, assign, readonly) NSUInteger rowNumber;
|
||||
|
||||
/// 列数
|
||||
@property (nonatomic, assign, readonly) NSUInteger colNumber;
|
||||
|
||||
@end
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// TLExpressionGroupModel+TLEmojiKB.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 2018/1/2.
|
||||
// Copyright © 2018年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLExpressionGroupModel+TLEmojiKB.h"
|
||||
|
||||
@implementation TLExpressionGroupModel (TLEmojiKB)
|
||||
|
||||
- (NSUInteger)rowNumber
|
||||
{
|
||||
if (self.type == TLEmojiTypeFace || self.type == TLEmojiTypeEmoji) {
|
||||
return 3;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
- (NSUInteger)colNumber
|
||||
{
|
||||
if (self.type == TLEmojiTypeFace || self.type == TLEmojiTypeEmoji) {
|
||||
return 7;
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
|
||||
- (NSUInteger)pageItemCount
|
||||
{
|
||||
if (self.type == TLEmojiTypeFace || self.type == TLEmojiTypeEmoji) {
|
||||
return self.rowNumber * self.colNumber - 1;
|
||||
}
|
||||
return self.rowNumber * self.colNumber;
|
||||
}
|
||||
|
||||
- (NSUInteger)pageNumber
|
||||
{
|
||||
return self.count / self.pageItemCount + (self.count % self.pageItemCount == 0 ? 0 : 1);
|
||||
}
|
||||
|
||||
@end
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// TLEmojiKeyboard+DisplayView.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/9/27.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLEmojiKeyboard.h"
|
||||
#import "TLEmojiGroupDisplayViewDelegate.h"
|
||||
|
||||
@interface TLEmojiKeyboard (DisplayView) <TLEmojiGroupDisplayViewDelegate>
|
||||
|
||||
@end
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// TLEmojiKeyboard+DisplayView.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/9/27.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLEmojiKeyboard+DisplayView.h"
|
||||
#import "TLExpressionGroupModel+TLEmojiKB.h"
|
||||
|
||||
@implementation TLEmojiKeyboard (DisplayView)
|
||||
|
||||
#pragma mark - # Delegate
|
||||
//MARK: TLEmojiGroupDisplayViewDelegate
|
||||
- (void)emojiGroupDisplayView:(TLEmojiGroupDisplayView *)displayView didClickedEmoji:(TLExpressionModel *)emoji
|
||||
{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(emojiKeyboard:didSelectedEmojiItem:)]) {
|
||||
[self.delegate emojiKeyboard:self didSelectedEmojiItem:emoji];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)emojiGroupDisplayViewDeleteButtonPressed:(TLEmojiGroupDisplayView *)displayView;
|
||||
{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(emojiKeyboardDeleteButtonDown)]) {
|
||||
[self.delegate emojiKeyboardDeleteButtonDown];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)emojiGroupDisplayView:(TLEmojiGroupDisplayView *)displayView didScrollToPageIndex:(NSInteger)pageIndex forGroupIndex:(NSInteger)groupIndex
|
||||
{
|
||||
TLExpressionGroupModel *group = self.emojiGroupData[groupIndex];
|
||||
if (self.curGroup != group) {
|
||||
self.curGroup = group;
|
||||
[self.pageControl setHidden:group.pageNumber <= 1];
|
||||
[self.pageControl setNumberOfPages:group.pageNumber];
|
||||
[self.groupControl selectEmojiGroupAtIndex:groupIndex];
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(emojiKeyboard:selectedEmojiGroupType:)]) {
|
||||
[self.delegate emojiKeyboard:self selectedEmojiGroupType:group.type];
|
||||
}
|
||||
}
|
||||
[self.pageControl setCurrentPage:pageIndex];
|
||||
|
||||
}
|
||||
|
||||
static UICollectionViewCell *lastCell;
|
||||
- (void)emojiGroupDisplayView:(TLEmojiGroupDisplayView *)displayView didLongPressEmoji:(TLExpressionModel *)emoji atRect:(CGRect)rect
|
||||
{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(emojiKeyboard:didTouchEmojiItem:atRect:)]) {
|
||||
[self.delegate emojiKeyboard:self didTouchEmojiItem:emoji atRect:rect];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)emojiGroupDisplayViewDidStopLongPressEmoji:(TLEmojiGroupDisplayView *)displayView
|
||||
{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(emojiKeyboardCancelTouchEmojiItem:)]) {
|
||||
[self.delegate emojiKeyboardCancelTouchEmojiItem:self];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// TLEmojiKeyboard+EmojiGroupControl.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/17.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLEmojiKeyboard.h"
|
||||
|
||||
@interface TLEmojiKeyboard (EmojiGroupControl) <TLEmojiGroupControlDelegate>
|
||||
|
||||
@end
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// TLEmojiKeyboard+EmojiGroupControl.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/17.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLEmojiKeyboard+EmojiGroupControl.h"
|
||||
#import "TLExpressionGroupModel+TLEmojiKB.h"
|
||||
|
||||
@implementation TLEmojiKeyboard (EmojiGroupControl)
|
||||
|
||||
#pragma mark - Delegate
|
||||
//MARK: TLEmojiGroupControlDelegate
|
||||
- (void)emojiGroupControl:(TLEmojiGroupControl *)emojiGroupControl didSelectedGroup:(TLExpressionGroupModel *)group
|
||||
{
|
||||
// 显示Group表情
|
||||
self.curGroup = group;
|
||||
[self.displayView scrollToEmojiGroupAtIndex:[self.emojiGroupData indexOfObject:group]];
|
||||
[self.pageControl setNumberOfPages:group.pageNumber];
|
||||
[self.pageControl setCurrentPage:0];
|
||||
// 更新chatBar的textView状态
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(emojiKeyboard:selectedEmojiGroupType:)]) {
|
||||
[self.delegate emojiKeyboard:self selectedEmojiGroupType:group.type];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)emojiGroupControlEditMyEmojiButtonDown:(TLEmojiGroupControl *)emojiGroupControl
|
||||
{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(emojiKeyboardMyEmojiEditButtonDown)]) {
|
||||
[self.delegate emojiKeyboardMyEmojiEditButtonDown];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)emojiGroupControlEditButtonDown:(TLEmojiGroupControl *)emojiGroupControl
|
||||
{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(emojiKeyboardEmojiEditButtonDown)]) {
|
||||
[self.delegate emojiKeyboardEmojiEditButtonDown];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)emojiGroupControlSendButtonDown:(TLEmojiGroupControl *)emojiGroupControl
|
||||
{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(emojiKeyboardSendButtonDown)]) {
|
||||
[self.delegate emojiKeyboardSendButtonDown];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// TLEmojiKeyboard.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/17.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLBaseKeyboard.h"
|
||||
#import "TLEmojiKeyboardDelegate.h"
|
||||
#import "TLEmojiGroupControl.h"
|
||||
#import "TLEmojiGroupDisplayView.h"
|
||||
|
||||
@interface TLEmojiKeyboard : TLBaseKeyboard
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray *emojiGroupData;
|
||||
|
||||
@property (nonatomic, assign) id<TLEmojiKeyboardDelegate> delegate;
|
||||
|
||||
@property (nonatomic, strong) TLExpressionGroupModel *curGroup;
|
||||
|
||||
@property (nonatomic, strong) TLEmojiGroupDisplayView *displayView;
|
||||
|
||||
@property (nonatomic, strong) UIPageControl *pageControl;
|
||||
|
||||
@property (nonatomic, strong) TLEmojiGroupControl *groupControl;
|
||||
|
||||
+ (TLEmojiKeyboard *)keyboard;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,121 @@
|
||||
//
|
||||
// TLEmojiKeyboard.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/17.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLEmojiKeyboard.h"
|
||||
#import "TLEmojiKeyboard+DisplayView.h"
|
||||
#import "TLEmojiKeyboard+EmojiGroupControl.h"
|
||||
#import "TLChatMacros.h"
|
||||
|
||||
static TLEmojiKeyboard *emojiKB;
|
||||
|
||||
@implementation TLEmojiKeyboard
|
||||
|
||||
+ (TLEmojiKeyboard *)keyboard
|
||||
{
|
||||
static dispatch_once_t once;
|
||||
dispatch_once(&once, ^{
|
||||
emojiKB = [[TLEmojiKeyboard alloc] init];
|
||||
});
|
||||
return emojiKB;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
[self setBackgroundColor:[UIColor colorGrayForChatBar]];
|
||||
[self addSubview:self.displayView];
|
||||
[self addSubview:self.pageControl];
|
||||
[self addSubview:self.groupControl];
|
||||
[self p_addMasonry];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setEmojiGroupData:(NSMutableArray *)emojiGroupData
|
||||
{
|
||||
_emojiGroupData = emojiGroupData;
|
||||
[self.displayView setData:emojiGroupData];
|
||||
[self.groupControl setEmojiGroupData:emojiGroupData];
|
||||
}
|
||||
|
||||
#pragma mark - # Public Methods
|
||||
- (void)reset
|
||||
{
|
||||
// [self.collectionView scrollRectToVisible:CGRectMake(0, 0, self.collectionView.width, self.collectionView.height) animated:NO];
|
||||
}
|
||||
|
||||
#pragma mark - # Event Response
|
||||
- (void)pageControlChanged:(UIPageControl *)pageControl
|
||||
{
|
||||
// [self.collectionView scrollRectToVisible:CGRectMake(SCREEN_WIDTH * pageControl.currentPage, 0, SCREEN_WIDTH, HEIGHT_PAGECONTROL) animated:YES];
|
||||
}
|
||||
|
||||
#pragma mark - # Private Methods
|
||||
- (void)p_addMasonry
|
||||
{
|
||||
[self.displayView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(self);
|
||||
make.left.and.right.mas_equalTo(self);
|
||||
make.bottom.mas_equalTo(self.pageControl.mas_top);
|
||||
}];
|
||||
[self.pageControl mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.and.right.mas_equalTo(self);
|
||||
make.bottom.mas_equalTo(self.groupControl.mas_top);
|
||||
make.height.mas_equalTo(20);
|
||||
}];
|
||||
[self.groupControl mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.and.right.and.bottom.mas_equalTo(self);
|
||||
make.height.mas_equalTo(37);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)rect
|
||||
{
|
||||
[super drawRect:rect];
|
||||
// 顶部直线
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
CGContextSetLineWidth(context, 0.5);
|
||||
CGContextSetStrokeColorWithColor(context, [UIColor colorGrayLine].CGColor);
|
||||
CGContextBeginPath(context);
|
||||
CGContextMoveToPoint(context, 0, 0);
|
||||
CGContextAddLineToPoint(context, SCREEN_WIDTH, 0);
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
#pragma mark - # Getter
|
||||
- (TLEmojiGroupDisplayView *)displayView
|
||||
{
|
||||
if (_displayView == nil) {
|
||||
_displayView = [[TLEmojiGroupDisplayView alloc] init];
|
||||
[_displayView setDelegate:self];
|
||||
}
|
||||
return _displayView;
|
||||
}
|
||||
|
||||
- (UIPageControl *)pageControl
|
||||
{
|
||||
if (_pageControl == nil) {
|
||||
_pageControl = [[UIPageControl alloc] init];
|
||||
_pageControl.centerX = self.centerX;
|
||||
[_pageControl setPageIndicatorTintColor:[UIColor colorGrayLine]];
|
||||
[_pageControl setCurrentPageIndicatorTintColor:[UIColor grayColor]];
|
||||
[_pageControl addTarget:self action:@selector(pageControlChanged:) forControlEvents:UIControlEventValueChanged];
|
||||
}
|
||||
return _pageControl;
|
||||
}
|
||||
|
||||
- (TLEmojiGroupControl *)groupControl
|
||||
{
|
||||
if (_groupControl == nil) {
|
||||
_groupControl = [[TLEmojiGroupControl alloc] init];
|
||||
[_groupControl setDelegate:self];
|
||||
}
|
||||
return _groupControl;
|
||||
}
|
||||
|
||||
@end
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// TLMoreKeyboardCell.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/18.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TLMoreKeyboardItem.h"
|
||||
|
||||
@interface TLMoreKeyboardCell : UICollectionViewCell
|
||||
|
||||
@property (nonatomic, strong) TLMoreKeyboardItem *item;
|
||||
|
||||
@property (nonatomic, strong) void(^clickBlock)(TLMoreKeyboardItem *item);
|
||||
|
||||
@end
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
//
|
||||
// TLMoreKeyboardCell.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/18.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLMoreKeyboardCell.h"
|
||||
#import "UIImage+Color.h"
|
||||
|
||||
@interface TLMoreKeyboardCell()
|
||||
|
||||
@property (nonatomic, strong) UIButton *iconButton;
|
||||
|
||||
@property (nonatomic, strong) UILabel *titleLabel;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLMoreKeyboardCell
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self.contentView addSubview:self.iconButton];
|
||||
[self.contentView addSubview:self.titleLabel];
|
||||
[self p_addMasonry];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setItem:(TLMoreKeyboardItem *)item
|
||||
{
|
||||
_item = item;
|
||||
if (item == nil) {
|
||||
[self.titleLabel setHidden:YES];
|
||||
[self.iconButton setHidden:YES];
|
||||
[self setUserInteractionEnabled:NO];
|
||||
return;
|
||||
}
|
||||
[self setUserInteractionEnabled:YES];
|
||||
[self.titleLabel setHidden:NO];
|
||||
[self.iconButton setHidden:NO];
|
||||
[self.titleLabel setText:item.title];
|
||||
[self.iconButton setImage:[UIImage imageNamed:item.imagePath] forState:UIControlStateNormal];
|
||||
}
|
||||
|
||||
#pragma mark - Event Response -
|
||||
- (void)iconButtonDown:(UIButton *)sender
|
||||
{
|
||||
self.clickBlock(self.item);
|
||||
}
|
||||
|
||||
#pragma mark - Private Methods -
|
||||
- (void)p_addMasonry
|
||||
{
|
||||
[self.iconButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(self.contentView);
|
||||
make.centerX.mas_equalTo(self.contentView);
|
||||
make.width.mas_equalTo(self.contentView);
|
||||
make.height.mas_equalTo(self.iconButton.mas_width);
|
||||
}];
|
||||
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.mas_equalTo(self.contentView);
|
||||
make.bottom.mas_equalTo(self.contentView);
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Getter -
|
||||
- (UIButton *)iconButton
|
||||
{
|
||||
if (_iconButton == nil) {
|
||||
_iconButton = [[UIButton alloc] init];
|
||||
[_iconButton.layer setMasksToBounds:YES];
|
||||
[_iconButton.layer setCornerRadius:5.0f];
|
||||
[_iconButton.layer setBorderWidth:BORDER_WIDTH_1PX];
|
||||
[_iconButton.layer setBorderColor:[UIColor grayColor].CGColor];
|
||||
[_iconButton setBackgroundImage:[UIImage imageWithColor:[UIColor colorGrayLine]] forState:UIControlStateHighlighted];
|
||||
[_iconButton addTarget:self action:@selector(iconButtonDown:) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _iconButton;
|
||||
}
|
||||
|
||||
- (UILabel *)titleLabel
|
||||
{
|
||||
if (_titleLabel == nil) {
|
||||
_titleLabel = [[UILabel alloc] init];
|
||||
[_titleLabel setFont:[UIFont systemFontOfSize:12.0f]];
|
||||
[_titleLabel setTextColor:[UIColor grayColor]];
|
||||
}
|
||||
return _titleLabel;
|
||||
}
|
||||
|
||||
@end
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// TLMoreKeyboardDelegate.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/20.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "TLMoreKeyboardItem.h"
|
||||
|
||||
@protocol TLMoreKeyboardDelegate <NSObject>
|
||||
@optional
|
||||
- (void)moreKeyboard:(id)keyboard didSelectedFunctionItem:(TLMoreKeyboardItem *)funcItem;
|
||||
|
||||
@end
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// TLMoreKeyboardItem.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/18.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef NS_ENUM(NSUInteger, TLMoreKeyboardItemType) {
|
||||
TLMoreKeyboardItemTypeImage,
|
||||
TLMoreKeyboardItemTypeCamera,
|
||||
TLMoreKeyboardItemTypeVideo,
|
||||
TLMoreKeyboardItemTypeVideoCall,
|
||||
TLMoreKeyboardItemTypeWallet,
|
||||
TLMoreKeyboardItemTypeTransfer,
|
||||
TLMoreKeyboardItemTypePosition,
|
||||
TLMoreKeyboardItemTypeFavorite,
|
||||
TLMoreKeyboardItemTypeBusinessCard,
|
||||
TLMoreKeyboardItemTypeVoice,
|
||||
TLMoreKeyboardItemTypeCards,
|
||||
};
|
||||
|
||||
@interface TLMoreKeyboardItem : NSObject
|
||||
|
||||
@property (nonatomic, assign) TLMoreKeyboardItemType type;
|
||||
|
||||
@property (nonatomic, strong) NSString *title;
|
||||
|
||||
@property (nonatomic, strong) NSString *imagePath;
|
||||
|
||||
+ (TLMoreKeyboardItem *)createByType:(TLMoreKeyboardItemType)type title:(NSString *)title imagePath:(NSString *)imagePath;
|
||||
|
||||
@end
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// TLMoreKeyboardItem.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/18.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLMoreKeyboardItem.h"
|
||||
|
||||
@implementation TLMoreKeyboardItem
|
||||
|
||||
|
||||
+ (TLMoreKeyboardItem *)createByType:(TLMoreKeyboardItemType)type title:(NSString *)title imagePath:(NSString *)imagePath
|
||||
{
|
||||
TLMoreKeyboardItem *item = [[TLMoreKeyboardItem alloc] init];
|
||||
item.type = type;
|
||||
item.title = title;
|
||||
item.imagePath = imagePath;
|
||||
return item;
|
||||
}
|
||||
|
||||
@end
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// TLMoreKeyboard+CollectionView.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/17.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLMoreKeyboard.h"
|
||||
|
||||
@interface TLMoreKeyboard (CollectionView) <UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>
|
||||
|
||||
@property (nonatomic, assign, readonly) NSInteger pageItemCount;
|
||||
|
||||
- (void)registerCellClass;
|
||||
|
||||
@end
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
//
|
||||
// TLMoreKeyboard+CollectionView.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/17.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLMoreKeyboard+CollectionView.h"
|
||||
#import "TLMoreKeyboardCell.h"
|
||||
|
||||
#define SPACE_TOP 15
|
||||
#define WIDTH_CELL 60
|
||||
|
||||
@implementation TLMoreKeyboard (CollectionView)
|
||||
|
||||
#pragma mark - Public Methods -
|
||||
- (void)registerCellClass
|
||||
{
|
||||
[self.collectionView registerClass:[TLMoreKeyboardCell class] forCellWithReuseIdentifier:@"TLMoreKeyboardCell"];
|
||||
}
|
||||
|
||||
#pragma mark - Delegate -
|
||||
//MARK: UICollectionViewDataSource
|
||||
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
|
||||
{
|
||||
return self.chatMoreKeyboardData.count / self.pageItemCount + (self.chatMoreKeyboardData.count % self.pageItemCount == 0 ? 0 : 1);
|
||||
}
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
|
||||
{
|
||||
return self.pageItemCount;
|
||||
}
|
||||
|
||||
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
TLMoreKeyboardCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TLMoreKeyboardCell" forIndexPath:indexPath];
|
||||
NSUInteger index = indexPath.section * self.pageItemCount + indexPath.row;
|
||||
NSUInteger tIndex = [self p_transformIndex:index]; // 矩阵坐标转置
|
||||
if (tIndex >= self.chatMoreKeyboardData.count) {
|
||||
[cell setItem:nil];
|
||||
}
|
||||
else {
|
||||
[cell setItem:self.chatMoreKeyboardData[tIndex]];
|
||||
}
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[cell setClickBlock:^(TLMoreKeyboardItem *sItem) {
|
||||
if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(moreKeyboard:didSelectedFunctionItem:)]) {
|
||||
[weakSelf.delegate moreKeyboard:weakSelf didSelectedFunctionItem:sItem];
|
||||
}
|
||||
}];
|
||||
return cell;
|
||||
}
|
||||
|
||||
//MARK: UICollectionViewDelegateFlowLayout
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
return CGSizeMake(WIDTH_CELL, (collectionView.height - SPACE_TOP) / 2 * 0.93);
|
||||
}
|
||||
|
||||
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
|
||||
{
|
||||
return (collectionView.width - WIDTH_CELL * self.pageItemCount / 2) / (self.pageItemCount / 2 + 1);
|
||||
}
|
||||
|
||||
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
|
||||
{
|
||||
return (collectionView.height - SPACE_TOP) / 2 * 0.07;
|
||||
}
|
||||
|
||||
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
|
||||
{
|
||||
CGFloat space = (collectionView.width - WIDTH_CELL * self.pageItemCount / 2) / (self.pageItemCount / 2 + 1);
|
||||
return UIEdgeInsetsMake(SPACE_TOP, space, 0, space);
|
||||
}
|
||||
//Mark: UIScrollViewDelegate
|
||||
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
|
||||
{
|
||||
[self.pageControl setCurrentPage:(int)(scrollView.contentOffset.x / scrollView.width)];
|
||||
}
|
||||
|
||||
#pragma mark - Private Methods -
|
||||
- (NSUInteger)p_transformIndex:(NSUInteger)index
|
||||
{
|
||||
NSUInteger page = index / self.pageItemCount;
|
||||
index = index % self.pageItemCount;
|
||||
NSUInteger x = index / 2;
|
||||
NSUInteger y = index % 2;
|
||||
return self.pageItemCount / 2 * y + x + page * self.pageItemCount;
|
||||
}
|
||||
|
||||
#pragma mark - # Getter
|
||||
- (NSInteger)pageItemCount
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// TLMoreKeyboard.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/17.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLBaseKeyboard.h"
|
||||
#import "TLKeyboardDelegate.h"
|
||||
#import "TLMoreKeyboardDelegate.h"
|
||||
#import "TLMoreKeyboardItem.h"
|
||||
|
||||
@interface TLMoreKeyboard : TLBaseKeyboard
|
||||
|
||||
@property (nonatomic, assign) id<TLMoreKeyboardDelegate> delegate;
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray *chatMoreKeyboardData;
|
||||
|
||||
@property (nonatomic, strong) UICollectionView *collectionView;
|
||||
|
||||
@property (nonatomic, strong) UIPageControl *pageControl;
|
||||
|
||||
+ (TLMoreKeyboard *)keyboard;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,120 @@
|
||||
//
|
||||
// TLMoreKeyboard.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/17.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLMoreKeyboard.h"
|
||||
#import "TLMoreKeyboard+CollectionView.h"
|
||||
#import "TLChatMacros.h"
|
||||
|
||||
static TLMoreKeyboard *moreKB;
|
||||
|
||||
@implementation TLMoreKeyboard
|
||||
|
||||
+ (TLMoreKeyboard *)keyboard
|
||||
{
|
||||
static dispatch_once_t once;
|
||||
dispatch_once(&once, ^{
|
||||
moreKB = [[TLMoreKeyboard alloc] init];
|
||||
});
|
||||
return moreKB;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
[self setBackgroundColor:[UIColor colorGrayForChatBar]];
|
||||
[self addSubview:self.collectionView];
|
||||
[self addSubview:self.pageControl];
|
||||
[self p_addMasonry];
|
||||
|
||||
[self registerCellClass];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CGFloat)keyboardHeight
|
||||
{
|
||||
return HEIGHT_CHAT_KEYBOARD;
|
||||
}
|
||||
|
||||
#pragma mark - # Public Methods
|
||||
- (void)setChatMoreKeyboardData:(NSMutableArray *)chatMoreKeyboardData
|
||||
{
|
||||
_chatMoreKeyboardData = chatMoreKeyboardData;
|
||||
[self.collectionView reloadData];
|
||||
NSUInteger pageNumber = chatMoreKeyboardData.count / self.pageItemCount + (chatMoreKeyboardData.count % self.pageItemCount == 0 ? 0 : 1);
|
||||
[self.pageControl setNumberOfPages:pageNumber];
|
||||
}
|
||||
|
||||
- (void)reset
|
||||
{
|
||||
[self.collectionView scrollRectToVisible:CGRectMake(0, 0, self.collectionView.width, self.collectionView.height) animated:NO];
|
||||
}
|
||||
|
||||
#pragma mark - # Event Response
|
||||
- (void)pageControlChanged:(UIPageControl *)pageControl
|
||||
{
|
||||
[self.collectionView scrollRectToVisible:CGRectMake(self.collectionView.width * pageControl.currentPage, 0, self.collectionView.width, self.collectionView.height) animated:YES];
|
||||
}
|
||||
|
||||
#pragma mark - Private Methods -
|
||||
- (void)p_addMasonry
|
||||
{
|
||||
[self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(self);
|
||||
make.left.and.right.mas_equalTo(self);
|
||||
make.bottom.mas_equalTo(-25);
|
||||
}];
|
||||
[self.pageControl mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.and.right.mas_equalTo(self);
|
||||
make.height.mas_equalTo(20);
|
||||
make.bottom.mas_equalTo(-2);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)rect
|
||||
{
|
||||
[super drawRect:rect];
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
CGContextSetLineWidth(context, 0.5);
|
||||
CGContextSetStrokeColorWithColor(context, [UIColor colorGrayLine].CGColor);
|
||||
CGContextBeginPath(context);
|
||||
CGContextMoveToPoint(context, 0, 0);
|
||||
CGContextAddLineToPoint(context, SCREEN_WIDTH, 0);
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
#pragma mark - # Getter
|
||||
- (UICollectionView *)collectionView
|
||||
{
|
||||
if (_collectionView == nil) {
|
||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||
[layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
|
||||
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||
[_collectionView setBackgroundColor:[UIColor clearColor]];
|
||||
[_collectionView setPagingEnabled:YES];
|
||||
[_collectionView setDataSource:self];
|
||||
[_collectionView setDelegate:self];
|
||||
[_collectionView setShowsHorizontalScrollIndicator:NO];
|
||||
[_collectionView setShowsHorizontalScrollIndicator:NO];
|
||||
[_collectionView setScrollsToTop:NO];
|
||||
}
|
||||
return _collectionView;
|
||||
}
|
||||
|
||||
- (UIPageControl *)pageControl
|
||||
{
|
||||
if (_pageControl == nil) {
|
||||
_pageControl = [[UIPageControl alloc] init];
|
||||
[_pageControl setPageIndicatorTintColor:[UIColor colorGrayLine]];
|
||||
[_pageControl setCurrentPageIndicatorTintColor:[UIColor grayColor]];
|
||||
[_pageControl addTarget:self action:@selector(pageControlChanged:) forControlEvents:UIControlEventValueChanged];
|
||||
}
|
||||
return _pageControl;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// TLBaseKeyboard.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/8/8.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TLChatMacros.h"
|
||||
#import "TLKeyboardDelegate.h"
|
||||
#import "TLKeyboardProtocol.h"
|
||||
|
||||
@interface TLBaseKeyboard : UIView <TLKeyboardProtocol>
|
||||
|
||||
/// 是否正在展示
|
||||
@property (nonatomic, assign, readonly) BOOL isShow;
|
||||
|
||||
/// 键盘事件回调
|
||||
@property (nonatomic, weak) id<TLKeyboardDelegate> keyboardDelegate;
|
||||
|
||||
/**
|
||||
* 显示键盘(在keyWindow上)
|
||||
*
|
||||
* @param animation 是否显示动画
|
||||
*/
|
||||
- (void)showWithAnimation:(BOOL)animation;
|
||||
|
||||
/**
|
||||
* 显示键盘
|
||||
*
|
||||
* @param view 父view
|
||||
* @param animation 是否显示动画
|
||||
*/
|
||||
- (void)showInView:(UIView *)view withAnimation:(BOOL)animation;
|
||||
|
||||
/**
|
||||
* 键盘消失
|
||||
*
|
||||
* @param animation 是否显示消失动画
|
||||
*/
|
||||
- (void)dismissWithAnimation:(BOOL)animation;
|
||||
|
||||
/**
|
||||
* 重置键盘
|
||||
*/
|
||||
- (void)reset;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,112 @@
|
||||
//
|
||||
// TLBaseKeyboard.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/8/8.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLBaseKeyboard.h"
|
||||
|
||||
@implementation TLBaseKeyboard
|
||||
|
||||
#pragma mark - # Public Methods
|
||||
- (void)showWithAnimation:(BOOL)animation
|
||||
{
|
||||
[self showInView:[UIApplication sharedApplication].keyWindow withAnimation:animation];
|
||||
}
|
||||
|
||||
- (void)showInView:(UIView *)view withAnimation:(BOOL)animation
|
||||
{
|
||||
if (_isShow) {
|
||||
return;
|
||||
}
|
||||
_isShow = YES;
|
||||
if (self.keyboardDelegate && [self.keyboardDelegate respondsToSelector:@selector(chatKeyboardWillShow:animated:)]) {
|
||||
[self.keyboardDelegate chatKeyboardWillShow:self animated:animation];
|
||||
}
|
||||
[view addSubview:self];
|
||||
CGFloat keyboardHeight = [self keyboardHeight];
|
||||
[self mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.and.right.mas_equalTo(view);
|
||||
make.height.mas_equalTo(keyboardHeight);
|
||||
make.bottom.mas_equalTo(view).mas_offset(keyboardHeight);
|
||||
}];
|
||||
[view layoutIfNeeded];
|
||||
|
||||
if (animation) {
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
[self mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.bottom.mas_equalTo(view);
|
||||
}];
|
||||
[view layoutIfNeeded];
|
||||
if (self.keyboardDelegate && [self.keyboardDelegate respondsToSelector:@selector(chatKeyboard:didChangeHeight:)]) {
|
||||
[self.keyboardDelegate chatKeyboard:self didChangeHeight:view.height - self.y];
|
||||
}
|
||||
} completion:^(BOOL finished) {
|
||||
if (self.keyboardDelegate && [self.keyboardDelegate respondsToSelector:@selector(chatKeyboardDidShow:animated:)]) {
|
||||
[self.keyboardDelegate chatKeyboardDidShow:self animated:animation];
|
||||
}
|
||||
}];
|
||||
}
|
||||
else {
|
||||
[self mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.bottom.mas_equalTo(view);
|
||||
}];
|
||||
[view layoutIfNeeded];
|
||||
if (self.keyboardDelegate && [self.keyboardDelegate respondsToSelector:@selector(chatKeyboardDidShow:animated:)]) {
|
||||
[self.keyboardDelegate chatKeyboardDidShow:self animated:animation];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dismissWithAnimation:(BOOL)animation
|
||||
{
|
||||
if (!_isShow) {
|
||||
if (!animation) {
|
||||
[self removeFromSuperview];
|
||||
}
|
||||
return;
|
||||
}
|
||||
_isShow = NO;
|
||||
if (self.keyboardDelegate && [self.keyboardDelegate respondsToSelector:@selector(chatKeyboardWillDismiss:animated:)]) {
|
||||
[self.keyboardDelegate chatKeyboardWillDismiss:self animated:animation];
|
||||
}
|
||||
if (animation) {
|
||||
CGFloat keyboardHeight = [self keyboardHeight];
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
[self mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.bottom.mas_equalTo(self.superview).mas_offset(keyboardHeight);
|
||||
}];
|
||||
[self.superview layoutIfNeeded];
|
||||
if (self.keyboardDelegate && [self.keyboardDelegate respondsToSelector:@selector(chatKeyboard:didChangeHeight:)]) {
|
||||
[self.keyboardDelegate chatKeyboard:self didChangeHeight:self.superview.height - self.y];
|
||||
}
|
||||
} completion:^(BOOL finished) {
|
||||
[self removeFromSuperview];
|
||||
if (self.keyboardDelegate && [self.keyboardDelegate respondsToSelector:@selector(chatKeyboardDidDismiss:animated:)]) {
|
||||
[self.keyboardDelegate chatKeyboardDidDismiss:self animated:animation];
|
||||
}
|
||||
}];
|
||||
}
|
||||
else {
|
||||
[self removeFromSuperview];
|
||||
if (self.keyboardDelegate && [self.keyboardDelegate respondsToSelector:@selector(chatKeyboardDidDismiss:animated:)]) {
|
||||
[self.keyboardDelegate chatKeyboardDidDismiss:self animated:animation];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)reset
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#pragma mark - # ZZKeyboardProtocol
|
||||
- (CGFloat)keyboardHeight
|
||||
{
|
||||
return HEIGHT_CHAT_KEYBOARD;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// TLKeyboardDelegate.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/17.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@protocol TLKeyboardDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
@optional
|
||||
- (void)chatKeyboardWillShow:(id)keyboard animated:(BOOL)animated;
|
||||
|
||||
- (void)chatKeyboardDidShow:(id)keyboard animated:(BOOL)animated;
|
||||
|
||||
- (void)chatKeyboardWillDismiss:(id)keyboard animated:(BOOL)animated;
|
||||
|
||||
- (void)chatKeyboardDidDismiss:(id)keyboard animated:(BOOL)animated;
|
||||
|
||||
- (void)chatKeyboard:(id)keyboard didChangeHeight:(CGFloat)height;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// TLKeyboardProtocol.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/8/8.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@protocol TLKeyboardProtocol <NSObject>
|
||||
|
||||
@required;
|
||||
- (CGFloat)keyboardHeight;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// TLChatMacros.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/19.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef TLChatMacros_h
|
||||
#define TLChatMacros_h
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#define HEIGHT_CHATBAR_TEXTVIEW 36.0f
|
||||
#define HEIGHT_MAX_CHATBAR_TEXTVIEW 111.5f
|
||||
#define HEIGHT_CHAT_KEYBOARD 215.0f
|
||||
|
||||
typedef NS_ENUM(NSInteger, TLEmojiType) {
|
||||
TLEmojiTypeEmoji,
|
||||
TLEmojiTypeFavorite,
|
||||
TLEmojiTypeFace,
|
||||
TLEmojiTypeImage,
|
||||
TLEmojiTypeImageWithTitle,
|
||||
TLEmojiTypeOther,
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, TLChatBarStatus) {
|
||||
TLChatBarStatusInit,
|
||||
TLChatBarStatusVoice,
|
||||
TLChatBarStatusEmoji,
|
||||
TLChatBarStatusMore,
|
||||
TLChatBarStatusKeyboard,
|
||||
};
|
||||
|
||||
|
||||
#endif /* TLChatMacros_h */
|
||||
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// TLChatUserProtocol.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/5/6.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef NS_ENUM(NSInteger, TLChatUserType) {
|
||||
TLChatUserTypeUser = 0,
|
||||
TLChatUserTypeGroup,
|
||||
};
|
||||
|
||||
|
||||
@protocol TLChatUserProtocol <NSObject>
|
||||
|
||||
@property (nonatomic, strong, readonly) NSString *chat_userID;
|
||||
|
||||
@property (nonatomic, strong, readonly) NSString *chat_username;
|
||||
|
||||
@property (nonatomic, strong, readonly) NSString *chat_avatarURL;
|
||||
|
||||
@property (nonatomic, strong, readonly) NSString *chat_avatarPath;
|
||||
|
||||
@property (nonatomic, assign, readonly) NSInteger chat_userType;
|
||||
|
||||
@optional;
|
||||
- (id)groupMemberByID:(NSString *)userID;
|
||||
|
||||
- (NSArray *)groupMembers;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// TLGroup+ChatModel.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/5/6.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLGroup.h"
|
||||
#import "TLChatUserProtocol.h"
|
||||
|
||||
@interface TLGroup (ChatModel) <TLChatUserProtocol>
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,49 @@
|
||||
|
||||
//
|
||||
// TLGroup+ChatModel.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/5/6.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLGroup+ChatModel.h"
|
||||
|
||||
@implementation TLGroup (ChatModel)
|
||||
|
||||
- (NSString *)chat_userID
|
||||
{
|
||||
return self.groupID;
|
||||
}
|
||||
|
||||
- (NSString *)chat_username
|
||||
{
|
||||
return self.groupName;
|
||||
}
|
||||
|
||||
- (NSString *)chat_avatarURL
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *)chat_avatarPath
|
||||
{
|
||||
return self.groupAvatarPath;
|
||||
}
|
||||
|
||||
- (NSInteger)chat_userType
|
||||
{
|
||||
return TLChatUserTypeGroup;
|
||||
}
|
||||
|
||||
- (id)groupMemberByID:(NSString *)userID
|
||||
{
|
||||
return [self memberByUserID:userID];
|
||||
}
|
||||
|
||||
- (NSArray *)groupMembers
|
||||
{
|
||||
return self.users;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// TLUser+ChatModel.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/5/6.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLUser.h"
|
||||
#import "TLChatUserProtocol.h"
|
||||
|
||||
@interface TLUser (ChatModel) <TLChatUserProtocol>
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// TLUser+ChatModel.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/5/6.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLUser+ChatModel.h"
|
||||
|
||||
@implementation TLUser (ChatModel)
|
||||
|
||||
- (NSString *)chat_userID
|
||||
{
|
||||
return self.userID;
|
||||
}
|
||||
|
||||
- (NSString *)chat_username
|
||||
{
|
||||
return self.showName;
|
||||
}
|
||||
|
||||
- (NSString *)chat_avatarURL
|
||||
{
|
||||
return self.avatarURL;
|
||||
}
|
||||
|
||||
- (NSString *)chat_avatarPath
|
||||
{
|
||||
return self.avatarPath;
|
||||
}
|
||||
|
||||
- (NSInteger)chat_userType
|
||||
{
|
||||
return TLChatUserTypeUser;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// TLChatViewController+Delegate.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/17.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLChatViewController.h"
|
||||
|
||||
@interface TLChatViewController (Delegate)
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,101 @@
|
||||
//
|
||||
// TLChatViewController+Delegate.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/3/17.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLChatViewController+Delegate.h"
|
||||
#import "TLExpressionViewController.h"
|
||||
#import "TLMyExpressionViewController.h"
|
||||
#import "TLUserDetailViewController.h"
|
||||
#import <MWPhotoBrowser/MWPhotoBrowser.h>
|
||||
#import "NSFileManager+TLChat.h"
|
||||
|
||||
@interface TLChatViewController ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLChatViewController (Delegate)
|
||||
|
||||
#pragma mark - Delegate -
|
||||
//MARK: TLMoreKeyboardDelegate
|
||||
- (void)moreKeyboard:(id)keyboard didSelectedFunctionItem:(TLMoreKeyboardItem *)funcItem
|
||||
{
|
||||
if (funcItem.type == TLMoreKeyboardItemTypeCamera || funcItem.type == TLMoreKeyboardItemTypeImage) {
|
||||
UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
|
||||
if (funcItem.type == TLMoreKeyboardItemTypeCamera) {
|
||||
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
|
||||
[imagePickerController setSourceType:UIImagePickerControllerSourceTypeCamera];
|
||||
}
|
||||
else {
|
||||
[TLUIUtility showAlertWithTitle:@"错误" message:@"相机初始化失败"];
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
[imagePickerController setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
|
||||
}
|
||||
[self presentViewController:imagePickerController animated:YES completion:nil];
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[imagePickerController.rac_imageSelectedSignal subscribeNext:^(id x) {
|
||||
[imagePickerController dismissViewControllerAnimated:YES completion:^{
|
||||
UIImage *image = [x objectForKey:UIImagePickerControllerOriginalImage];
|
||||
[weakSelf sendImageMessage:image];
|
||||
}];
|
||||
} completed:^{
|
||||
[imagePickerController dismissViewControllerAnimated:YES completion:nil];
|
||||
}];
|
||||
}
|
||||
else {
|
||||
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:[NSString stringWithFormat:@"选中”%@“ 按钮", funcItem.title] delegate:nil cancelButtonTitle:@"确定" otherButtonTitles: nil];
|
||||
[alert show];
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: TLEmojiKeyboardDelegate
|
||||
- (void)emojiKeyboardEmojiEditButtonDown
|
||||
{
|
||||
TLExpressionViewController *expressionVC = [[TLExpressionViewController alloc] init];
|
||||
UINavigationController *navC = [[UINavigationController alloc] initWithRootViewController:expressionVC];
|
||||
[self presentViewController:navC animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)emojiKeyboardMyEmojiEditButtonDown
|
||||
{
|
||||
TLMyExpressionViewController *myExpressionVC = [[TLMyExpressionViewController alloc] init];
|
||||
UINavigationController *navC = [[UINavigationController alloc] initWithRootViewController:myExpressionVC];
|
||||
[self presentViewController:navC animated:YES completion:nil];
|
||||
}
|
||||
|
||||
//MARK: TLChatViewControllerProxy
|
||||
- (void)didClickedUserAvatar:(TLUser *)user
|
||||
{
|
||||
TLUserDetailViewController *detailVC = [[TLUserDetailViewController alloc] initWithUserModel:user];
|
||||
PushVC(detailVC);
|
||||
}
|
||||
|
||||
- (void)didClickedImageMessages:(NSArray *)imageMessages atIndex:(NSInteger)index
|
||||
{
|
||||
NSMutableArray *data = [[NSMutableArray alloc] init];
|
||||
for (TLMessage *message in imageMessages) {
|
||||
NSURL *url;
|
||||
if ([(TLImageMessage *)message imagePath]) {
|
||||
NSString *imagePath = [NSFileManager pathUserChatImage:[(TLImageMessage *)message imagePath]];
|
||||
url = [NSURL fileURLWithPath:imagePath];
|
||||
}
|
||||
else {
|
||||
url = TLURL([(TLImageMessage *)message imageURL]);
|
||||
}
|
||||
|
||||
MWPhoto *photo = [MWPhoto photoWithURL:url];
|
||||
[data addObject:photo];
|
||||
}
|
||||
MWPhotoBrowser *browser = [[MWPhotoBrowser alloc] initWithPhotos:data];
|
||||
[browser setDisplayNavArrows:YES];
|
||||
[browser setCurrentPhotoIndex:index];
|
||||
UINavigationController *broserNavC = [[UINavigationController alloc] initWithRootViewController:browser];
|
||||
[self presentViewController:broserNavC animated:NO completion:nil];
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// TLChatViewController.h
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/15.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLChatBaseViewController.h"
|
||||
|
||||
@interface TLChatViewController : TLChatBaseViewController
|
||||
|
||||
- (instancetype)initWithUserId:(NSString *)userId;
|
||||
|
||||
- (instancetype)initWithGroupId:(NSString *)groupId;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,120 @@
|
||||
//
|
||||
// TLChatViewController.m
|
||||
// TLChat
|
||||
//
|
||||
// Created by 李伯坤 on 16/2/15.
|
||||
// Copyright © 2016年 李伯坤. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TLChatViewController.h"
|
||||
#import "TLChatViewController+Delegate.h"
|
||||
#import "TLChatDetailViewController.h"
|
||||
#import "TLChatGroupDetailViewController.h"
|
||||
#import "TLMoreKBHelper.h"
|
||||
#import "TLEmojiKBHelper.h"
|
||||
#import "TLUserHelper.h"
|
||||
#import "TLChatNotificationKey.h"
|
||||
#import "TLFriendHelper.h"
|
||||
|
||||
static TLChatViewController *chatVC;
|
||||
|
||||
@interface TLChatViewController()
|
||||
|
||||
@property (nonatomic, strong) TLMoreKBHelper *moreKBhelper;
|
||||
|
||||
@property (nonatomic, strong) TLEmojiKBHelper *emojiKBHelper;
|
||||
|
||||
@property (nonatomic, strong) UIBarButtonItem *rightBarButton;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TLChatViewController
|
||||
|
||||
- (instancetype)initWithUserId:(NSString *)userId
|
||||
{
|
||||
if (self = [super init]) {
|
||||
TLUser *user = [[TLFriendHelper sharedFriendHelper] getFriendInfoByUserID:userId];
|
||||
self.partner = user;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithGroupId:(NSString *)groupId
|
||||
{
|
||||
if (self = [super init]) {
|
||||
TLGroup *group = [[TLFriendHelper sharedFriendHelper] getGroupInfoByGroupID:groupId];
|
||||
self.partner = group;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
[self.navigationItem setRightBarButtonItem:self.rightBarButton];
|
||||
|
||||
self.user = (id<TLChatUserProtocol>)[TLUserHelper sharedHelper].user;
|
||||
self.moreKBhelper = [[TLMoreKBHelper alloc] init];
|
||||
[self setChatMoreKeyboardData:self.moreKBhelper.chatMoreKeyboardData];
|
||||
self.emojiKBHelper = [TLEmojiKBHelper sharedKBHelper];
|
||||
TLWeakSelf(self);
|
||||
[self.emojiKBHelper emojiGroupDataByUserID:[TLUserHelper sharedHelper].userID complete:^(NSMutableArray *emojiGroups) {
|
||||
[weakself setChatEmojiKeyboardData:emojiGroups];
|
||||
}];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resetChatVC) name:NOTI_CHAT_VIEW_RESET object:nil];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
[MobClick beginLogPageView:@"ChatVC"];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewWillDisappear:animated];
|
||||
[MobClick endLogPageView:@"ChatVC"];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
#ifdef DEBUG_MEMERY
|
||||
NSLog(@"dealloc ChatVC");
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma mark - # Public Methods
|
||||
- (void)setPartner:(id<TLChatUserProtocol>)partner
|
||||
{
|
||||
[super setPartner:partner];
|
||||
if ([partner chat_userType] == TLChatUserTypeUser) {
|
||||
[self.rightBarButton setImage:[UIImage imageNamed:@"nav_chat_single"]];
|
||||
}
|
||||
else if ([partner chat_userType] == TLChatUserTypeGroup) {
|
||||
[self.rightBarButton setImage:[UIImage imageNamed:@"nav_chat_multi"]];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - # Event Response
|
||||
- (void)rightBarButtonDown:(UINavigationBar *)sender
|
||||
{
|
||||
if ([self.partner chat_userType] == TLChatUserTypeUser) {
|
||||
TLChatDetailViewController *chatDetailVC = [[TLChatDetailViewController alloc] initWithUserModel:(TLUser *)self.partner];
|
||||
PushVC(chatDetailVC);
|
||||
}
|
||||
else if ([self.partner chat_userType] == TLChatUserTypeGroup) {
|
||||
TLChatGroupDetailViewController *chatGroupDetailVC = [[TLChatGroupDetailViewController alloc] initWithGroupModel:(TLGroup *)self.partner];
|
||||
PushVC(chatGroupDetailVC);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - # Getter
|
||||
- (UIBarButtonItem *)rightBarButton
|
||||
{
|
||||
if (_rightBarButton == nil) {
|
||||
_rightBarButton = [[UIBarButtonItem alloc] initWithImage:nil style:UIBarButtonItemStylePlain target:self action:@selector(rightBarButtonDown:)];
|
||||
}
|
||||
return _rightBarButton;
|
||||
}
|
||||
@end
|
||||
Reference in New Issue
Block a user