简单版QQ聊天

来源:互联网 发布:吾知所以距子矣的距 编辑:程序博客网 时间:2024/04/18 13:36



                                                


这个小的应用中主要用到了  MVC的开发模式, 还有 代理和通知机制

这个程序中包含了2个模型 modle 和modleframe

modle中存放的是 每一条消息的详细内容


 modle类

typedef enum                      

{

    JMMessageModelTypeMe =0,

    JMMessageModelTypeOther

}JMMessageModelType;


@interface JMgessageModle :NSObject

@property (nonatomic,copy)NSString *text;                  //信息内容

@property (nonatomic,copy)NSString *time;                  //发送时间

@property (nonatomic,assign) JMMessageModelType type;      //头像的的宏, 0是自己,1是他人

@property (nonatomic,assign) BOOL hiddenTime;              //是否显示时间,当俩条小时是一样的时候就隐藏时间

- (instancetype)initWithDict:(NSDictionary *)dict;          //字典转模型的方法

+ (instancetype)modeWithDict:(NSDictionary *)dict;          //工厂方法

@end

------------------------------------------------------------------------------------------------

#import "JMgessageModle.h"


@implementation JMgessageModle


- (instancetype)initWithDict:(NSDictionary *)dict;

{

   if(self = [superinit])

    {

        [selfsetValuesForKeysWithDictionary:dict];   //KVC机制使成员变量和字段中得值,自动对应起来

    }

    return  self;

}

+ (instancetype)modeWithDict:(NSDictionary *)dict;    //类方法,(工厂方法)


{

   return [[selfalloc]initWithDict:dict];

    

}

@end



modleframe类

#import <Foundation/Foundation.h>                    //用来设置每个modle的位置(大小和位置)

@class JMgessageModle;

@interface JMgessageModleFrame :NSObject

#define JMTextFont [UIFont systemFontOfSize:15]


//设置每个modle的位置与大小

//声明一个模型属性

@property (nonatomic,strong) JMgessageModle *gessage;     

//设置时间的位置

@property (nonatomic,assign,readonly)CGRect timeF;        


//设置头像的位置

@property (nonatomic,assign,readonly)CGRect iconF;       


//设置正文的位置

@property (nonatomic,assign,readonly)CGRect textF;       


//设置cell

@property (nonatomic,assign,readonly)CGFloat cellHeight;


@end

-----------------------------------------------------------------------------

#import "JMgessageModleFrame.h"

#import "JMgessageModle.h"


@implementation JMgessageModleFrame


//重写magestset方法给每个模型设置位置和大小


- (void)setGessage:(JMgessageModle *)gessage

{

    //千万不要忘记给属性赋值,这个错误很坑爹的

   _gessage = gessage;

    //获取屏幕的宽度,

    CGFloat screenWidth = [UIScreenmainScreen].bounds.size.width;

    

    //table 距离两边的间隙

   CGFloat padding = 10;

    

    //1 时间的设置

   if(NO == gessage.hiddenTime)

    {

    CGFloat timeX =0; //时间是放爱一个lable中得,里面的文字居中就行,所以在这里不用设

   CGFloat timeY = 0;

   CGFloat timeW = screenWidth;

   CGFloat timeH = 30;

   _timeF = CGRectMake(timeX, timeY, timeW, timeH);

    }

    //2 头像的位置

    

    CGFloat iconX =0; //时间是放爱一个lable中得,里面的文字居中就行,所以在这里不用设

    CGFloat iconY =CGRectGetMaxY(_timeF) + padding;//因为头像在时间的下面,所以,就取是时间的Y再加上间隙

   CGFloat iconW = 30;

   CGFloat iconH = 30;

    //头像的位置首先判断一下,这个头像是自检的还是别人的,自己的在左边,别人的就再右边

    if(JMMessageModelTypeMe== _gessage.type)

    {

        iconX = screenWidth - padding -iconW;

    }

    else  //他人得头像, 就是一个间隙

    {

        iconX = padding;

    }

    

   _iconF = CGRectMake(iconX, iconY, iconH, iconW);

    //3 正文的位置

    NSDictionary *dict =@{NSFontAttributeName:JMTextFont};//JMTextFont是个宏,设置字体大小

    //给下面的那个计算文字高度的方法,设置文字的字体,

   CGSize maxSize = CGSizeMake(200,MAXFLOAT);// 设置要显示文字的宽度,高不限制

    

    //

    CGSize textSize = [_gessage.textboundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:dictcontext:nil].size;

   CGFloat textW = textSize.width +40;

   CGFloat textH = textSize.height +40;

   CGFloat textY = iconY;

   CGFloat textX = 0;

    if (JMMessageModelTypeMe ==_gessage.type) {

       // 自己发的

        // x = 头像x - 间隙 - 文本的宽度

        textX = iconX - padding - textW;

    }else

    {

       // 别人发的

        // x = 头像最大的X + 间隙

        textX =CGRectGetMaxX(_iconF) + padding;

    }

   _textF = CGRectMake(textX, textY, textW, textH);

   //行高

   CGFloat maxIconY = CGRectGetMaxY(_iconF);

   CGFloat maxTextY = CGRectGetMaxY(_textF);

    

    // _cellHeight = (maxIconY > maxTextY?  (maxIconY + padding) :  (maxIconY + padding));

   _cellHeight = MAX(maxIconY, maxTextY) + padding;

    

}

@end



#import "JMgessageModleFrame.h"

#import <UIKit/UIKit.h>


@interface JMmessageCell :UITableViewCell

+ (instancetype)cellWithTableView:(UITableView *)tableView;//重写cellwith方法


@property (nonatomic,strong) JMgessageModleFrame *messageFrame;

@end

---------------------------------------------------------------------------------

#import "JMmessageCell.h"

#import "JMgessageModleFrame.h"

#import "JMgessageModle.h"

@interface JMmessageCell()


@property (nonatomic,weak)UILabel *timeLable;//cell中设置一个显示时间的控件

@property (nonatomic,weak)UIImageView *imangeView;// 头像

@property (nonatomic,weak)UIButton *textButton;

@end


@implementation JMmessageCell

+ (instancetype)cellWithTableView:(UITableView *)tableView//创建cell

{

   static NSString *identifier =@"message";

   JMmessageCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];

   if (cell == nil) {

        cell = [[JMmessageCellalloc] initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:identifier];

    }

   return cell;

}


- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier

{

    //添加所有需要显⽰示的⼦子控件(不需要设置⼦子控件的数据和frame,⼦子控件要添加 contentView)重写这个方法的意思就是重新购置一个Cell 自己定义一个cell的风格

   self = [superinitWithStyle:style reuseIdentifier:reuseIdentifier];

   if(self)

    {

    //设置时间的样式 :因为每行都有一个显示时间的控件

   UILabel *timeLabel = [[UILabelalloc]init];

    timeLabel.font = [UIFontsystemFontOfSize:13.0];//设置字体

    timeLabel.textAlignment =NSTextAlignmentCenter;//设置居中对齐

    //timeLabel.backgroundColor = [UIColor grayColor];//这种背景颜色

    [self.contentViewaddSubview:timeLabel]; //把控件添加到控制器中

       self.timeLable = timeLabel;

    

    // 2.添加正文

   UIButton *contentBtn = [[UIButtonalloc] init];//设置正文按钮

    contentBtn.titleLabel.font =JMTextFont; //这种字体

    [contentBtn setTitleColor:[UIColorblackColor] forState:UIControlStateNormal];

    // 设置自动换行

    contentBtn.titleLabel.numberOfLines =0;

    [self.contentViewaddSubview:contentBtn];

   _textButton = contentBtn;

    

    // 3.添加头像

   UIImageView *iconView = [[UIImageViewalloc] init];

    [self.contentViewaddSubview:iconView];

   _imangeView = iconView;

    

    // 4.清空cell的背景颜色

    self.backgroundColor = [UIColorclearColor];

        

       self.textButton.contentEdgeInsets =UIEdgeInsetsMake(20,20, 20, 20);


    }

    return self;

}

- (void)setMessageFrame:(JMgessageModleFrame *)messageFrame

{

   

   _messageFrame = messageFrame;//传入一个模型坐标

       /*

     5.重写frame模型属性的setter⽅方法:在这个⽅方法中设置⼦子控件的显⽰示数据和frame

     // 1.设置子控件的数据

     [self settingData];

     // 2.设置子控件的frame

     [self settingFrame];

     NSLog(@"%@_________%@---%d", messagea.text,messagea.time,messagea.type);


     */

    // 0. 获取数据模型

    JMgessageModle *mange =_messageFrame.gessage;

    

    // 1.设置时间的值与位置

    

   self.timeLable.text = mange.time;

    

    self.timeLable.frame =_messageFrame.timeF;

    

    // 2 设置头像

       if(JMMessageModelTypeMe == mange.type)

    {

       self.imangeView.image = [UIImageimageNamed:@"me"];

    }

   else

        

    {

       self.imangeView.image = [UIImageimageNamed:@"other"];

    }

    

    self.imangeView.frame =_messageFrame.iconF;

        

    // 3 设置文字

    [self.textButtonsetTitle:mange.textforState:UIControlStateNormal];

    self.textButton.frame =_messageFrame.textF;

    

    //设置背景图片

    

    if (JMMessageModelTypeMe == mange.type)

    {

       // 自己发的

       UIImage *norImage = [UIImageimageNamed:@"chat_send_nor"];

       CGFloat w = norImage.size.width *0.5;

       CGFloat h = norImage.size.height *0.5;

        UIImage *newImage = [norImageresizableImageWithCapInsets:UIEdgeInsetsMake(h, w, h, w)resizingMode:UIImageResizingModeStretch];

        [self.textButtonsetBackgroundImage:newImage forState:UIControlStateNormal];

        

    }

   else

    {

       UIImage *norImage = [UIImageimageNamed:@"chat_recive_nor"];

       CGFloat w = norImage.size.width *0.5;

       CGFloat h = norImage.size.height *0.5;

        UIImage *newImage = [norImageresizableImageWithCapInsets:UIEdgeInsetsMake(h, w, h, w)resizingMode:UIImageResizingModeStretch];

        [self.textButtonsetBackgroundImage:newImage forState:UIControlStateNormal];

    }

    

    }


@end



//

//  JMViewController.m

//  QQ聊天

//

//  Created by wjm on 14-5-28.

//  Copyright (c) 2014 itheima. All rights reserved.

//

#import "JMgessageModle.h"

#import "JMgessageModleFrame.h"

#import "JMViewController.h"

#import "JMmessageCell.h"

@interface JMViewController ()<UITableViewDataSource,UITableViewDelegate,UITextFieldDelegate>

@property (nonatomic,weak)IBOutlet UITableView *tableView;

@property (nonatomic,strong)NSMutableArray *messages;

@property (nonatomic,strong)NSDictionary *aggess;


@property (weak, nonatomic) IBOutletUITextField *inputTextField;

@end

@implementation JMViewController

//懒加载


- (NSMutableArray *)messages

{

       if (_messages ==nil) {

           NSString *fullPath = [[NSBundlemainBundle] pathForResource:@"messages.plist"ofType:nil];

           NSArray *dictArray = [NSArrayarrayWithContentsOfFile:fullPath];

           NSMutableArray *models = [NSMutableArrayarrayWithCapacity:dictArray.count];

           JMgessageModle *previousMessage = nil;

           for (NSDictionary *dictin dictArray) {

               // 创建数据模型

               JMgessageModle *messagea11 = [JMgessageModlemodeWithDict:dict];

               //获取上一次的时间

                               // 创建frame模型

                messagea11.hiddenTime = [messagea11.timeisEqualToString:previousMessage.time];

                

                JMgessageModleFrame *mfm = [[JMgessageModleFramealloc] init];

                

                mfm.gessage = messagea11;

                [modelsaddObject:mfm];

                previousMessage = messagea11;

                

            }

           self.messages = [modelsmutableCopy];

        }

       return _messages;

    }

//懒加载2

- (NSDictionary *)aggess

{

   if (_aggess ==nil) {

       NSString *fullPath = [[NSBundlemainBundle] pathForResource:@"aggess.plist"ofType:nil];

        _aggess = [NSDictionarydictionaryWithContentsOfFile:fullPath];

    }

    return_aggess;

}


- (void)viewDidLoad

{

    [superviewDidLoad];

   self.tableView.rowHeight =100;

   self.tableView.dataSource =self;

    

    // 设置隐藏分割线

    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;

    //设置隐藏垂直的滚动条

    self.tableView.showsVerticalScrollIndicator =NO;

    self.tableView.allowsSelection =NO;

    // 设置tableview的背景颜色

    self.tableView.backgroundColor = [UIColorcolorWithRed:224/255.0green:224/255.0blue:224/255.0alpha:1];

    [[NSNotificationCenter defaultCenter]addObserver:selfselector:@selector(keyboardWillChange:)name:UIKeyboardWillChangeFrameNotification object:nil];

    

   UIView *view = [[UIViewalloc] initWithFrame:CGRectMake(0,0, 5, 0)];//输入框光标到右边的距离

    //    view.backgroundColor = [UIColor redColor];

   self.inputTextField.leftView = view;

    //设置左边视图的显示模式

    self.inputTextField.leftViewMode = UITextFieldViewModeAlways;

    

    // 监听键盘send按钮的点击


     self.inputTextField.delegate =self;



}

- (BOOL)textFieldShouldReturn:(UITextField *)textField//键盘输入文本的操作

{

    

    [selfaddMessage:textField.texttype:JMMessageModelTypeMe];

    

    

   NSString *result = nil;

    

   for (int i =0; i < textField.text.length; i++)

    {

       NSString *str = [textField.textsubstringWithRange:NSMakeRange(i,1)];

        

        result =self.aggess[str];

        

       if(result != nil)

        {

           break;

        }else{

            result =[NSStringstringWithFormat:@"%@个毛线啊" , textField.text];

        }

    }

    

    //NSString *str = [NSString stringWithFormat:@"%@个毛线啊" , textField.text];

    

    [selfaddMessage:result type:JMMessageModelTypeOther];

    

    [self.tableViewreloadData]; //清除数据

    

    textField.text =nil;

    

   NSIndexPath * indexpath = [NSIndexPathindexPathForRow:self.messages.count-1inSection:0];

    

    [self.tableViewscrollToRowAtIndexPath:indexpath atScrollPosition:UITableViewScrollPositionBottom animated:YES];

    

    return YES;

}

- (void)addMessage:(NSString *)content type:(JMMessageModelType)type

{

    // 1.修改模型(创建模型,并且将模型保存到数组中)

    

   NSDate *date = [NSDatedate];//获取系统时间

    NSDateFormatter *datestyle = [[NSDateFormatteralloc] init];//创建一个时间系那是公式

    datestyle.dateFormat =@"HH:mm:ss:dd/MM";//时间格式

   NSString *content1 = [datestyle stringFromDate:date];//把时间按这个格式显示出来

    

    JMgessageModle *message = [[JMgessageModlealloc]init];//新建一个modle

    message.time =content1;

    message.text = content;

    message.type = type;

    

    JMgessageModleFrame *modleframe = [[JMgessageModleFramealloc]init];

    

    modleframe.gessage = message;

    

    [self.messagesaddObject:modleframe];//把这个modleframe添加到模型数组中

    

    // 获取上一次的message

}

- (void)keyboardWillChange:(NSNotification *)notification   //键盘控制器

{

    

   NSDictionary *dict  = notification.userInfo;

    CGRect keyboardFrame = [dict[UIKeyboardFrameEndUserInfoKey]CGRectValue];

   CGFloat keyboardY = keyboardFrame.origin.y;

    //获取动画执行时间

    CGFloat duration = [dict[UIKeyboardAnimationDurationUserInfoKey]doubleValue];

    // 2.计算需要移动的距离

   CGFloat translationY = keyboardY - self.view.frame.size.height;

    // 通过动画移动view

     输入框和键盘之间会由一条黑色的线条,产生线条的原因是键盘弹出时执行动画的节奏和我们让控制器view移动的动画的节奏不一致导致

     */

    [UIViewanimateWithDuration:duration delay:0.0options:7 <<16 animations:^{

        // 需要执行动画的代码

        self.view.transform = CGAffineTransformMakeTranslation(0, translationY);

    }completion:^(BOOL finished) {

        // 动画执行完毕执行的代码

    }];


}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

{

    

    return self.messages.count;  //tableView的组数

}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

        // 1.创建cell

   JMmessageCell *cell = [JMmessageCellcellWithTableView:tableView];

       // 2.设置数据

    cell.messageFrame =self.messages[indexPath.row];

    

        // 3.返回cell

   return cell;

    

}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

{

    // 1.取出frame模型

    JMgessageModleFrame *mf =self.messages[indexPath.row];

    // 2.返回对应行的高度

    return mf.cellHeight;

}


- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView

{

    [self.viewendEditing:YES];//隐藏键盘

}


- (BOOL)prefersStatusBarHidden

{

   return YES;  //状态栏不显示

}


@end





0 0
原创粉丝点击