iOS中QQ聊天界面发送消息及表情键盘的实现

//
//  ViewController.m
//  UIbiaoqingjianpan
//
//  Created by 张艳雪 on 15/12/28.
//  Copyright (c) 2015年 张艳雪. All rights reserved.
//

#import "ViewController.h"
#import "MyChatText.h"
#import "MyChatCell.h"

#define SCREEN_WIDTH self.view.frame.size.width
#define SCREEN_HEIGHT self.view.frame.size.height
//屏幕的宽高


@interface ViewController ()
@property (nonatomic,strong)UIScrollView *scrollView;
//表情键盘
/**
 *  表情键盘和键盘分页视图
 */
@property (nonatomic,strong)UIView *keyView;

//@property (nonatomic,strong)UITextField *textField;
@property (nonatomic,strong)UITextView *textView;
//输入框

@property (nonatomic,strong)UIButton *btn;
//发送按钮

/**
 *  表情按钮
 */
@property (nonatomic,strong)UIButton *imageBtn;

/**
 *  集合体View
 */
@property (nonatomic,strong)UIView *titleView;

/**
 *  表情分页控制器
 */
@property (nonatomic,strong)UIPageControl *pageControl;

/**
 *  聊天窗口
 */
@property (nonatomic,strong)UITableView *tableView;
/**
 *  聊天数据源
 */
@property (nonatomic,strong)NSMutableArray *dataArray;

///**
// *  记录聊天数据
// */
//@property (nonatomic,strong)NSMutableAttributedString *attString;
/**
 *  聊天视图
 */
@property (nonatomic,strong)UIView *chatView;
/**
 *  add提示
 */
@property (nonatomic,strong) UIAlertView *alertView;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    _dataArray = [[NSMutableArray alloc] init];

//-----------------------------集合体titleView此视图上面包括输入框和发送表情键盘调出按钮
    _titleView = [[UIView alloc] initWithFrame:CGRectMake(0, SCREEN_HEIGHT - 78, SCREEN_WIDTH, 78)];
    
    _titleView.backgroundColor = [UIColor colorWithRed:230/255.f green:236/255.f blue:232/255.f alpha:1];
    [self.view addSubview:_titleView];
//    -----------------------键盘出现消失的通知-------------------
    //(1)键盘即将显示的通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyBoardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    
    //(2)键盘即将隐藏的通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyBoardWillHide:) name:UIKeyboardWillHideNotification object:nil];
//    ------------------------创建表情键盘调用按钮和发送按钮---------------------
    
    [self createView];
//    ---------------------控件textView--------------height = 35
    [self createTextView];

    //调用方法创建scrollView
    [self createScrollView];
    
    //调用tableView聊天框
    [self createTableView];
    
    //调用额外功能的按钮      height = 43
    [self createAdd];

}
#pragma mark ----------第一部分 界面布置-----------------------------------------

- (void)createView{
    //    ------------------------创建表情按钮---------------------
    
    _imageBtn = [[UIButton alloc] initWithFrame:CGRectMake(13, 0, 35, 35)];
    
    _imageBtn.layer.cornerRadius = 15;
    
    [_imageBtn setBackgroundImage:[UIImage imageNamed:@"icon_05.png"] forState:UIControlStateNormal];
    
    _imageBtn.tintColor = [UIColor blackColor];
    
    [_imageBtn addTarget:self action:@selector(btnImageClick:) forControlEvents:UIControlEventTouchUpInside];
    
    [_titleView addSubview:_imageBtn];
//    ==========-===================
    //创建发送按钮
    _btn = [[UIButton alloc] initWithFrame:CGRectMake(SCREEN_WIDTH - 70, 0, 60, 35)];
    
    [_btn setTitle:@"发送" forState:UIControlStateNormal];
    
    _btn.layer.cornerRadius = 5;
    
    [_btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    
    _btn.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.2];
    
    [_btn addTarget:self action:@selector(sendBtn:) forControlEvents:UIControlEventTouchUpInside];
    
    [_titleView addSubview:_btn];

    
    
}

#pragma mark ------  创建textView
- (void)createTextView{
    //创建textfield
    _textView = [[UITextView alloc] initWithFrame:CGRectMake(55, 0, SCREEN_WIDTH - 140, 35)];
    
    //    _textField.backgroundColor = [UIColor yellowColor];
    
    _textView.font = [UIFont systemFontOfSize:30];
    _textView.layer.borderColor=[UIColor lightGrayColor].CGColor;
    _textView.layer.borderWidth =1.0;
    _textView.layer.cornerRadius =5.0;
    //设置代理 使_btn变色
    _textView.delegate = self;
    
    [_titleView addSubview:_textView];
}


#pragma mark ---------  创建scrollView(表情键盘)
- (void)createScrollView{
    
    _keyView = [[UIView alloc] initWithFrame:CGRectMake(0, SCREEN_HEIGHT, SCREEN_WIDTH, 200)];
    [self.view addSubview:_keyView];
    
    
//    ------------------------表情键盘 ---------------------------
    
    
    
    //1,创建scrollView
    _scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 200)];
    
    //2,创建viewA
    //表情的顺序(序号)
    NSInteger count = 1;
    
    UIView *viewA = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH * 3, 200)];
    for (int m = 0; m < 4; m++) {
        //每一页的表情
        UIView *viewB = [[UIView alloc] initWithFrame:CGRectMake(10 + SCREEN_WIDTH * m, 0, SCREEN_WIDTH, 200)];
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 7; j++) {
                UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(SCREEN_WIDTH/7 * j, 50 * i, SCREEN_WIDTH/10, SCREEN_WIDTH/10)];
                btn.layer.cornerRadius = SCREEN_WIDTH/10;
                
                if (i == 2&&j == 6) {//删除按钮
                    
                    //删除按钮的点击事件
                    [btn addTarget:self action:@selector(deleteBtn:) forControlEvents:UIControlEventTouchUpInside];
                    
                    [btn setBackgroundImage:[UIImage imageNamed:@"DeleteEmoticonBtn_ios7.png"] forState:UIControlStateNormal];
                    [viewB addSubview:btn];
                    break;
                }else{
                    
                    //表情按钮添加事件
                    [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
                    
                    [btn setBackgroundImage:[UIImage imageNamed:[NSString stringWithFormat:@"[Expression_%lu].png",count]] forState:UIControlStateNormal];
                    
                    [viewB addSubview:btn];
                    count++;
                }
            }
            
        }
        [viewA addSubview:viewB];
    }
    
    //隐藏滑动条
    _scrollView.showsHorizontalScrollIndicator = NO;
    _scrollView.showsVerticalScrollIndicator = NO;
    
    //开启翻页模式
    _scrollView.pagingEnabled = YES;
    
    [_scrollView addSubview:viewA];
    
    [self createPageControll];
    
    [_keyView addSubview:_scrollView];
    
    
    //设置scrollView可以滚动的范围
    _scrollView.contentSize = CGSizeMake(SCREEN_WIDTH * 3, 200);
    
    //关闭弹簧效果
    _scrollView.bounces = NO;
    
    //设置代理用于改变page
    _scrollView.delegate = self;
    
}

#pragma mark  -------  create pageControll(用于表情)
- (void)createPageControll{
    
    //1,创建
    _pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, 150, SCREEN_WIDTH, 30)];
    
    //2,设置点数
    _pageControl.numberOfPages = 3;
    
    //3,设置背景颜色
    _pageControl.backgroundColor = [UIColor clearColor];
    
    //4,选中某个点时候的颜色
    _pageControl.currentPageIndicatorTintColor = [UIColor blackColor];
    
    //5,设置页码指示器的颜色
    _pageControl.pageIndicatorTintColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.2];
    
    [_keyView addSubview:_pageControl];
    
}

#pragma mark ---------   创建tableView
- (void)createTableView{
    
    
    _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 44, SCREEN_WIDTH, SCREEN_HEIGHT - 122)];
    _tableView.delegate = self;
    _tableView.dataSource = self;
    //隐藏tableView的线
    _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    //    ---------测试---------------
    //#define COLORS arc4random()%256/255.0
    //
    //    _tableView.backgroundColor = [UIColor colorWithRed:COLORS green:COLORS blue:COLORS alpha:1];
    
    [self.view addSubview:_tableView];
    
    /**
     当触摸tableView时候隐藏键盘
     */
    UITapGestureRecognizer *tap=[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapDown)];
    [_tableView addGestureRecognizer:tap];
}
//=======================附加功能=======================
- (void)createAdd{
    
    UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(0, 35, SCREEN_WIDTH, 43)];
    
    [btn setBackgroundImage:[UIImage imageNamed:@"botton.png"] forState:UIControlStateNormal];
    
    [btn setTintColor:[UIColor blackColor]];
    
    
    [btn addTarget:self action:@selector(AddBtn:) forControlEvents:UIControlEventTouchUpInside];
    
    
    
    [_titleView addSubview:btn];
    
}
#pragma mark第二部分  按钮点击事件部分
#pragma mark -------------   调用表情出来的按钮点击事件
- (void)btnImageClick:(UIButton *)imageBtn{
    
    imageBtn.selected ^= 1;
    
    //标记imageBtn
    imageBtn.tag = 10;
    
    if (imageBtn.selected) {
        [self imageBtnUp];
    }else{
        [self imageBtnDown];
    }
    
}
//============================ 表情通过附件添加到textView=========================
#pragma mark -------- 删除表情按钮图片

- (void)deleteBtn:(UIButton *)deleteBtn{
    
    deleteBtn.selected ^= 1;
    
    /**
     *  判断删除按钮被选中并且textView的长度大于0
     */
    if (deleteBtn.selected&&(_textView.attributedText.length > 0)) {
        //获取表情
        NSMutableAttributedString *chatText=[[NSMutableAttributedString alloc]initWithAttributedString:_textView.attributedText];
        //删除最后一个
        [chatText deleteCharactersInRange:NSMakeRange(chatText.length-1, 1)];
        //传回去
        _textView.attributedText=chatText;
    }
}


#pragma mark ---------表情按钮图片事件
- (void)btnClick:(UIButton *)btn{
    
    btn.selected ^= 1;
    //获取原有的AttributedString
    NSMutableAttributedString * textChat = [[ NSMutableAttributedString alloc ] initWithAttributedString:_textView.attributedText];
    
    //获取按钮背景图片(即表情)
    UIImage *image = [btn backgroundImageForState:UIControlStateNormal];
    
    //创建并且初始化
    NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init];
    
    //设置image
    textAttachment.image=image;
    
    //附件大小
    textAttachment.bounds = CGRectMake(0, 0, 25, 25);
    
    //将附件转化为纯文本
    NSAttributedString *textAttachmentString=[NSAttributedString attributedStringWithAttachment:textAttachment];
    
    //增加到原来的基础上
    [textChat appendAttributedString:textAttachmentString];
    
    //以文本形式传给textView
    _textView.attributedText = textChat;
    
}

#pragma mark --------  附加功能按钮

- (void)AddBtn:(UIButton *)btn{
    
    btn.selected ^= 1;
    
    if (btn.selected) {
        [self createAlertView];
    }
    
}

#pragma mark ----------  发送按钮
- (void)sendBtn:(UIButton *)btn{
    
    [_chatView resignFirstResponder];
    
    /**
     *  判断textView长度是否为空
     */
    if (_textView.attributedText.length > 0) {
        MyChatText *txtContent = [[MyChatText alloc] init];
        //给对象添加内容
        txtContent.content = _textView.attributedText;
        _textView.attributedText = [[NSMutableAttributedString alloc]initWithString:@""];
        //存储cell所需数据
        [_dataArray addObject:txtContent];
        //添加新的一行row
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:_dataArray.count-1 inSection:0];
        [_tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
        //自动滚动到最底部
        [_tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
        
    }
    
    
}
#pragma mark第三部分代理部分

#pragma mark -------   scrollView代理
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
    
    //获取当前是第几页
    int page = _scrollView.contentOffset.x/SCREEN_WIDTH;
    
    //给page赋值
    _pageControl.currentPage = page;
    
}

#pragma mark --------  textView代理
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
    
    /**
     *  当textView有内容的时候让按钮背景颜色变为蓝色
     */
    _btn.backgroundColor = [UIColor colorWithRed:51/255.0 green:156/255.0 blue:249/255.0 alpha:1];
    
    return YES;
}

#pragma mark --------   tableView代理
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    MyChatText *MyChatText = [_dataArray objectAtIndex:indexPath.row];
    //计算content所占用大小
    
    CGSize size=[MyChatText.content boundingRectWithSize:CGSizeMake(150, 1000) options:NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesFontLeading | NSStringDrawingUsesLineFragmentOrigin context:nil].size;
    /**
     参数
     
     size
     
     宽高限制,用于计算文本绘制时占据的矩形块。
     
     options
     
     文本绘制时的附加选项。可能取值请参考“NSStringDrawingOptions”。
     
     context
     
     context上下文。包括一些信息,例如如何调整字间距以及缩放。最终,该对象包含的信息将用于文本绘制。该参数可为 nil 。
     
     返回值
     
     一个矩形,大小等于文本绘制完将占据的宽和高。
     */
    return size.height + 20 + 30+ 15 ;

}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    
    return _dataArray.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    
    static NSString *cellID = @"cellID";
    
    MyChatCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
    
    if (cell == nil) {
        cell = [[MyChatCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
    }
    
    MyChatText *ChatText = [_dataArray objectAtIndex:indexPath.row];
    
    //计算content所占用大小
    CGSize size=[ChatText.content boundingRectWithSize:CGSizeMake(150, 1000) options:NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesFontLeading | NSStringDrawingUsesLineFragmentOrigin context:nil].size;

    
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    
    //头像的位置受聊天气泡起始坐标的变化
    cell.rightHeadView.frame=CGRectMake(size.width+50 , 0 , 40 , 40);

    cell.rightHeadView.image=[UIImage imageNamed:@"icon.png"];

    //聊天视图受文本长度的影响变化frame
    cell.rightView.frame = CGRectMake(self.view.frame.size.width-10-size.width-25-63, 20, size.width+40, size.height+30);
    cell.rightTextLabel.frame = CGRectMake(15, 10, size.width, size.height);
    cell.rightTextLabel.attributedText = ChatText.content;



    return cell;
}



#pragma mark -------  提示对话框
- (void)createAlertView{
    // ============================== 自定义警告对话框 ===============================
    
    _alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"该功能暂时不支持" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:@"取消", nil];
    
    [self.view addSubview:_alertView];
    
    [_alertView show];
}



#pragma mark -第四部分视图上滑与下滑


#pragma mark -----------表情图起来与收回
- (void)imageBtnUp{
    /**
     *  取消系统键盘的第一响应
     */
    [_textView resignFirstResponder];
    
    CGRect rectKeylUp = _keyView.frame;
    
    CGRect rectViewUp = _titleView.frame;
    
    //tableView的高度变化
    
    CGRect rectTableView = _tableView.frame;
    
    rectKeylUp.origin.y = rectKeylUp.origin.y - 200;
    
    rectViewUp.origin.y = rectViewUp.origin.y - 200;
    
    rectTableView.size.height = rectTableView.size.height - 200;
    
    [UIView animateWithDuration:0.3 animations:^{
        
        _titleView.frame = rectViewUp;
        
        _keyView.frame = rectKeylUp;
        
        _tableView.frame = rectTableView;
        
    }];
    _imageBtn.backgroundColor = [UIColor colorWithRed:51/255.0 green:156/255.0 blue:249/255.0 alpha:1];
    
}
- (void)imageBtnDown{
    CGRect rectKeyDown = _keyView.frame;
    
    CGRect rectViewDown = _titleView.frame;
    
    //tableView的高度变化
    
    CGRect rectTableView = _tableView.frame;
    
    rectKeyDown.origin.y = rectKeyDown.origin.y + 200;
    
    rectViewDown.origin.y = rectViewDown.origin.y + 200;
    
    rectTableView.size.height = rectTableView.size.height + 200;
    
    [UIView animateWithDuration:0.3 animations:^{
        
        _titleView.frame = rectViewDown;
        
        _keyView.frame = rectKeyDown;
        
        _tableView.frame = rectTableView;
        
    }];
    _imageBtn.backgroundColor = [UIColor clearColor];
    
    
}



#pragma mark -- 键盘即将显示的通知方法

- (void)keyBoardWillShow:(NSNotification *)noti{
    //判断是否需要收回表情键盘
    if (_keyView.frame.origin.y < self.view.frame.size.height) {
        [self imageBtnDown];
        
        //取消imageBtn的选中状态,不然就消失了
        UIButton *btn = (UIButton *)[self.view viewWithTag:10];
        btn.selected = NO;
    }
    
    /**
     *  键盘滑出所需时间
     */
    NSTimeInterval time ;
    //time = [[noti.userInfo objectForKey:@"UIKeyboardAnimationDurationUserInfoKey"] doubleValue];
    [noti.userInfo[UIKeyboardAnimationDurationUserInfoKey] getValue:&time];
    
    CGRect keyBoardFrame;
    //用于记录键盘的坐标
    /**
     *  获取键盘的frame
     */
    [noti.userInfo[UIKeyboardFrameEndUserInfoKey] getValue:&keyBoardFrame];

    //获取集合视图的frame
    CGRect rect = _titleView.frame;
    
    /**
     *  tableView的frame
     */
    CGRect rectTableView = _tableView.frame;
    
    rectTableView.size.height = rectTableView.size.height - keyBoardFrame.size.height;

    
    rect.origin.y = keyBoardFrame.origin.y - rect.size.height;
    
    /**
     添加动画
     */
    
    [UIView animateWithDuration:time animations:^{
        /**
         *  改变视图位置
         */
        _titleView.frame = rect;
        
        _tableView.frame = rectTableView;
        
    }];

    
}
#pragma mark -- 键盘即将隐藏的通知方法

- (void)keyBoardWillHide:(NSNotification *)noti{
    
    //1.获取动画时间
    NSTimeInterval time;
    
    [noti.userInfo[UIKeyboardAnimationDurationUserInfoKey] getValue:&time];
    
    //2.获取键盘frame
    CGRect keyBoardFrame;
    
    [noti.userInfo[UIKeyboardFrameEndUserInfoKey] getValue:&keyBoardFrame];
    
    /**
        添加动画
     */
    [UIView animateWithDuration:time animations:^{
        _titleView.frame = CGRectMake(0, SCREEN_HEIGHT - 78, SCREEN_WIDTH, 78);
        
//        还原tableView
        _tableView.frame = CGRectMake(0, 44, SCREEN_WIDTH, SCREEN_HEIGHT - 122);
    }];
    
    
}
#pragma mark -----------  tableView手势 
- (void)tapDown{
    [_textView resignFirstResponder];
    //取消键盘第一响应
    
    //判断表情键盘是否在屏幕内
    if (_keyView.frame.origin.y < self.view.frame.size.height) {
        [self imageBtnDown];
        
        //取消imageBtn的选中状态,不然就消失了
        UIButton *btn = (UIButton *)[self.view viewWithTag:10];
        btn.selected = NO;
    }
}

#pragma mark ----------  touchbegain
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    
    [_textView resignFirstResponder];
    //取消键盘第一响应
    
    //判断表情键盘是否在屏幕内
    if (_keyView.frame.origin.y < self.view.frame.size.height) {
        [self imageBtnDown];
        
        //取消imageBtn的选中状态,不然就消失了
        UIButton *btn = (UIButton *)[self.view viewWithTag:10];
        btn.selected = NO;
    }
}




- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end
//
//  MyChatCell.m
//  UIbiaoqingjianpan
//
//  Created by 张艳雪 on 16/1/3.
//  Copyright (c) 2016年 张艳雪. All rights reserved.
//

#import "MyChatCell.h"

@implementation MyChatCell

//创建cell时候调用
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        
        [self makeView];
        
    }
    return self;
}

-(void)makeView{
    UIImage *rightImage = [UIImage imageNamed:@"SenderTextNodeBkg.png"];
    //     ==============================按照内容进行不变形拉伸=========================
    rightImage = [rightImage stretchableImageWithLeftCapWidth:30 topCapHeight:35];
    //     ==============================增加气泡图片背景======================
    self.rightView = [[UIImageView alloc] init];
    self.rightView.image = rightImage;
    //    _rightView.backgroundColor = [UIColor redColor];
    [self.contentView addSubview:_rightView];
    
    //    =================================增加头像位于气泡右面==================
    self.rightHeadView=[[UIImageView alloc]init];
    self.rightHeadView.layer.masksToBounds=YES;
    self.rightHeadView.layer.cornerRadius=10;
    [_rightView addSubview:_rightHeadView];
    
    //    ==============================增加聊天内容================
    self.rightTextLabel = [[UILabel alloc] init];
    self.rightTextLabel.font = [UIFont systemFontOfSize:14];
    self.rightTextLabel.numberOfLines = 0;
    self.rightTextLabel.backgroundColor = [UIColor clearColor];
    [_rightView addSubview:_rightTextLabel];
}

- (void)awakeFromNib {
    // Initialization code
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

@end
//
//  MyChatText.h
//  UIbiaoqingjianpan
//
//  Created by 张艳雪 on 16/1/3.
//  Copyright (c) 2016年 张艳雪. All rights reserved.
//

#import 

@interface MyChatText : NSObject

@property(nonatomic,assign)BOOL isPic;

@property(nonatomic,copy)NSString *length;

@property(nonatomic,copy)NSString *height;


@property(nonatomic,copy)NSString *sender;

@property(nonatomic,copy)NSAttributedString *content;
@end

你可能感兴趣的:(iOS程序开发)