ios-day08-01(模仿QQ聊天界面。ios通知的使用(对键盘状态的监听)、枚举和分类的使用、拉伸图片、计算文本字符串的尺寸

源码下载地址:http://download.csdn.net/detail/liu537192/8471945


Demo效果图:



核心代码:

//
//  JLViewController.m
//  01-QQ
//
//  Created by XinYou on 15-3-3.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import "JLViewController.h"
#import "JLMessage.h"
#import "JLMessageFrame.h"
#import "JLMessageCell.h"

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

@property (nonatomic, strong) NSMutableArray *messageFrames;

@property (weak, nonatomic) IBOutlet UITextField *inputView;

@end

@implementation JLViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // 1,UITableView的设置
    // 设置数据源
    self.tableView.dataSource = self;
    // 设置代理
    self.tableView.delegate = self;
    // 设置tableView的背景色
    self.tableView.backgroundColor = [UIColor colorWithRed:235/255.0 green:235/255.0 blue:235/255.0 alpha:1];
    // 去除cell之间的分割线
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    // 将cell设置为不可选中(点击)
    self.tableView.allowsSelection = NO;
    
    // 2,监听键盘的通知,注册监听,一定要记得反注册
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
    
    // 3,设置文本框左边显示的view(因为光标太靠左,我们想让光标离UITextField左边有一段距离)
    // 在UITextField的左边放一个高度为0,宽度不为0的UIView来占据左边的一段空间
    self.inputView.leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 0)];
    // 设置leftView的显示模式,这里设置为总是显示(如果不设置,默认是不显示的)
    self.inputView.leftViewMode = UITextFieldViewModeAlways;
    
    // 4,设置UITextField的代理
    self.inputView.delegate = self;
    
}

/**
 *  当键盘的frame改变了(位置和尺寸)的时候调用
 *
 *  @param notification 通知包含的信息
 */
- (void)keyboardWillChangeFrame:(NSNotification *)notification{

    self.view.window.backgroundColor = self.tableView.backgroundColor;
    
    NSDictionary *userInfo = notification.userInfo;
    // 当键盘弹出的时候,userInfo:
    /**
     UIKeyboardAnimationCurveUserInfoKey = 7;// 动画执行的节奏
     UIKeyboardAnimationDurationUserInfoKey = "0.25"; // 键盘弹出和隐藏动画所需时间
     UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {320, 216}}";
     UIKeyboardCenterBeginUserInfoKey = "NSPoint: {160, 588}";
     UIKeyboardCenterEndUserInfoKey = "NSPoint: {160, 372}";
     UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 480}, {320, 216}}";
     UIKeyboardFrameChangedByUserInteraction = 0;
     UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 264}, {320, 216}}";
     */
    
    // 当键盘隐藏的时候,userInfo:
    /**
     UIKeyboardAnimationCurveUserInfoKey = 7;
     UIKeyboardAnimationDurationUserInfoKey = "0.25";
     UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {320, 216}}";
     UIKeyboardCenterBeginUserInfoKey = "NSPoint: {160, 372}";
     UIKeyboardCenterEndUserInfoKey = "NSPoint: {160, 588}";
     UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 264}, {320, 216}}";
     UIKeyboardFrameChangedByUserInteraction = 0;
     UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 480}, {320, 216}}";
     */
    
    // 1,取出键盘动画的时间
    CGFloat duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    // 2,取得键盘将要移动到的位置的frame
    CGRect keyboardFrame = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    
    // 3,计算控制器的view需要平移的距离
    CGFloat moveY = keyboardFrame.origin.y - self.view.frame.size.height;
    
    // 4,执行动画
    [UIView animateWithDuration:duration animations:^{
        self.view.transform = CGAffineTransformMakeTranslation(0, moveY);
    }];
}
/**
 *  在dealloc方法中反注册,移除对通知的监听
 */
- (void)dealloc{
    
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

// 隐藏状态栏
- (BOOL)prefersStatusBarHidden{

    return YES;
}

- (NSMutableArray *)messageFrames
{
    if (_messageFrames == nil) {
        NSArray *dictArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"messages.plist" ofType:nil]];
    
        NSMutableArray *tempArray = [NSMutableArray array];
        
        for (NSDictionary *dict in dictArray) {
            // 消息模型
            JLMessage *message = [JLMessage messageWithDict:dict];
            
            // 取出上一个模型
            JLMessageFrame *previousMessageFrame = [tempArray lastObject];
            JLMessage *previousMessage = previousMessageFrame.message;
            
            // 判断两个message的发送时间是否一致
            message.hideTime = [message.time isEqualToString:previousMessage.time];
            
            // frame模型
            JLMessageFrame *messageFrame = [[JLMessageFrame alloc] init];
            messageFrame.message = message;
            
            // 添加模型到数组
            [tempArray addObject:messageFrame];
        }
        _messageFrames = tempArray;
    }
    
    return _messageFrames;

}
/**
 *  发送一条消息
 */
- (void)sendMessage:(NSString *)text type:(JLMessageType)type{
    // 1,数据模型
    JLMessage *msg = [[JLMessage alloc] init];
    // 设置信息类型,是自己发送给别人
    msg.type = type;
    // 设置信息内容
    msg.text = text;
    // 设置信息发送时间
    NSDate *msgTime = [NSDate date];
    // 对当前时间进行格式化
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    formatter.dateFormat = @"HH:mm";
    msg.time = [formatter stringFromDate:msgTime];
    // 是否需要隐藏时间
    JLMessageFrame *previousFrame = [self.messageFrames lastObject];
    JLMessage *previousMsg = previousFrame.message;
    msg.hideTime = [msg.time isEqualToString:previousMsg.time];
    
    // 2,frame模型
    JLMessageFrame *msgFrame = [[JLMessageFrame alloc] init];
    msgFrame.message = msg;
    [self.messageFrames addObject:msgFrame];
    
    // 3,刷新表格
    [self.tableView reloadData];
    
    // 4,自动滚动到表格的最后一行
    NSIndexPath *path = [NSIndexPath indexPathForRow:self.messageFrames.count - 1 inSection:0];
    [self.tableView scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionBottom animated:YES];
    
}

#pragma mark -UITextField的代理方法
/**
 *  点击了手机键盘的最右下角的按钮
 */
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
    
    // 1,发送一条消息
    [self sendMessage:textField.text type:JLMessageTypeMeToOther];
    
    // 2,UITextField的文字
    self.inputView.text = nil;
    
    // 返回YES即可,不要问为什么
    return YES;
}

#pragma mark -数据源方法
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{

    return 1;
}

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


    return self.messageFrames.count;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    
    // 创建cell
    JLMessageCell *cell = [JLMessageCell cellWithTableView:tableView];
    
    // 给cell传递模型数据
    cell.messageFrame = self.messageFrames[indexPath.row];
    
    // 返回cell
    return cell;
}

#pragma mark -代理方法
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    JLMessageFrame *messageFrame = self.messageFrames[indexPath.row];
    
    return messageFrame.cellHeight;
}
/**
 *  当开始拖拽表格的时候就退出键盘
 */
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{

    // 退出键盘
    [self.view endEditing:YES];
}

@end

    
    
//
//  NSString+Extension.h
//  01-QQ
//
//  Created by XinYou on 15-3-3.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import 
    
    
     
     

// 给NSString这个类添加一个分类,让NSString这个类增加一个计算字符串尺寸的方法
@interface NSString (Extension)

/**
 *  返回字符串所占用的尺寸
 *
 *  @param font    字符串的字体
 *  @param maxSize 字符串的最大尺寸
 */
- (CGSize)sizeWithFont:(UIFont*)font maxSize:(CGSize)maxSize;

@end
//
//  NSString+Extension.m
//  01-QQ
//
//  Created by XinYou on 15-3-3.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import "NSString+Extension.h"

@implementation NSString (Extension)

- (CGSize)sizeWithFont:(UIFont *)font maxSize:(CGSize)maxSize{

    NSDictionary *attrs = @{NSFontAttributeName : font};
    return [self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size;
}

@end
//
//  UIImage+Extension.h
//  01-QQ
//
//  Created by XinYou on 15-3-4.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import 
     
     
      
      

// 给UIImage这个类添加分类,让UIImage这个类增加一个对图片进行拉伸的方法
@interface UIImage (Extension)
+ (UIImage *)resizableImage:(NSString *)name;
@end
//
//  UIImage+Extension.m
//  01-QQ
//
//  Created by XinYou on 15-3-4.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import "UIImage+Extension.h"

@implementation UIImage (Extension)

/**
 *  返回一张可以随意拉伸,但四个角不变形的图片
 *
 *  @param name 图片名字
 */
+ (UIImage *)resizableImage:(NSString *)name{

    UIImage *resPic = [UIImage imageNamed:name];
    
    CGFloat w = resPic.size.width * 0.5;
    CGFloat h = resPic.size.height * 0.5;
    
    UIImage *desPic = [resPic resizableImageWithCapInsets:UIEdgeInsetsMake(h, w, h, w)];
    
    return desPic;
}

@end
//
//  JLMessageCell.h
//  01-QQ
//
//  Created by XinYou on 15-3-3.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import 
      
      
       
       
@class JLMessageFrame;

@interface JLMessageCell : UITableViewCell

+ (instancetype)cellWithTableView:(UITableView *)tableView;

@property (nonatomic, strong) JLMessageFrame *messageFrame;

@end
//
//  JLMessageCell.m
//  01-QQ
//
//  Created by XinYou on 15-3-3.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import "JLMessageCell.h"
#import "JLMessage.h"
#import "JLMessageFrame.h"
#import "JLMessageCell.h"
#import "UIImage+Extension.h"

@interface JLMessageCell()
/**
 *  信息发送时间
 */
@property (nonatomic, weak) UILabel *timeView;
/**
 *  头像
 */
@property (nonatomic, weak) UIImageView *iconView;
/**
 *  信息内容
 */
@property (nonatomic, weak) UIButton *textView;

@end

@implementation JLMessageCell

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // 子控件的创建和初始化
        // 1,时间
        UILabel *timeView = [[UILabel alloc] init];
        // 设置文本居中显示
        timeView.textAlignment = NSTextAlignmentCenter;
        // 设置文本颜色
        timeView.textColor = [UIColor grayColor];
        // 设置文本字体
        timeView.font = [UIFont systemFontOfSize:13];
        
        [self.contentView addSubview:timeView];
        self.timeView = timeView;
        
        // 2,头像
        UIImageView *iconView = [[UIImageView alloc] init];
        [self.contentView addSubview:iconView];
        self.iconView = iconView;
        
        // 3,文本信息
        UIButton *textView = [[UIButton alloc] init];
        // 设置自动换行
        textView.titleLabel.numberOfLines = 0;
        // 设置字体
        textView.titleLabel.font = JLTextFont;
        // 设置文本距离UIButton的边距
        textView.contentEdgeInsets = UIEdgeInsetsMake(JLTextPadding, JLTextPadding, JLTextPadding, JLTextPadding);
        // 设置文本颜色
        [textView setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        [self.contentView addSubview:textView];
        self.textView = textView;
        
        // 4,清空cell的背景色,这样才能看见UITableView的背景色
        self.backgroundColor = [UIColor clearColor];
    }
    return self;
}

+ (instancetype)cellWithTableView:(UITableView *)tableView{

    static NSString *ID = @"message";
    JLMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell == nil) {
        cell = [[JLMessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    }
    
    return cell;
}

- (void)setMessageFrame:(JLMessageFrame *)messageFrame{
    // 固定写法
    _messageFrame = messageFrame;
    
    JLMessage *message = messageFrame.message;
    
    // 1,时间
    self.timeView.text = message.time;
    self.timeView.frame = messageFrame.timeF;
    
    // 2,头像
    NSString *icon = (message.type == JLMessageTypeMeToOther ? @"me" : @"other");
    self.iconView.image = [UIImage imageNamed:icon];
    self.iconView.frame = messageFrame.iconF;
    
    // 3,文本信息
    [self.textView setTitle:message.text forState:UIControlStateNormal];
    self.textView.frame = messageFrame.textF;
    
    // 4,正文的背景
    if (message.type == JLMessageTypeMeToOther) {// 自己发给别人,蓝色背景
        [self.textView setBackgroundImage:[UIImage resizableImage:@"chat_send_nor"] forState:UIControlStateNormal];
    }else{// 别人发给自己,白色背景
        [self.textView setBackgroundImage:[UIImage resizableImage:@"chat_recive_nor"] forState:UIControlStateNormal];
    }
}

@end
//
//  JLMessage.h
//  01-QQ
//
//  Created by XinYou on 15-3-3.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import 
       
       
        
        
//定义一个枚举
typedef enum {
    // 枚举中的第一个元素默认=0,第二个元素=1,依次递增,也可以不写
    JLMessageTypeMeToOther = 0,//自己发给别人
    JLMessageTypeOtherToMe// 别人发给自己
} JLMessageType;

@interface JLMessage : NSObject
/**
 *  信息内容
 */
@property (nonatomic, copy) NSString *text;
/**
 *  信息发送时间
 */
@property (nonatomic, copy) NSString *time;
/**
 *  信息的类型(类型有两种,一种是自己发送给别人的信息,一种是别人发送给自己的信息)
 */
@property (nonatomic, assign) JLMessageType type;
/**
 *  是否隐藏时间(如果连续多条信息的时间相同,只能有一条信息显示时间)
 */
@property (nonatomic, assign) BOOL hideTime;

+ (instancetype)messageWithDict:(NSDictionary *)dict;

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

@end
//
//  JLMessage.m
//  01-QQ
//
//  Created by XinYou on 15-3-3.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import "JLMessage.h"

@implementation JLMessage

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

    if (self = [super init]) {
        [self setValuesForKeysWithDictionary:dict];
    }
    
    return self;
}


+ (instancetype)messageWithDict:(NSDictionary *)dict{

    return [[self alloc] initWithDict:dict];
}

@end
//
//  JLMessageFrame.h
//  01-QQ
//
//  Created by XinYou on 15-3-3.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

// 正文的字体
#define JLTextFont [UIFont systemFontOfSize:15]

// 正文的内边距
#define JLTextPadding 20

#import 
        
        
          @class JLMessage; @interface JLMessageFrame : NSObject /** * 头像的frame */ @property (nonatomic, assign, readonly) CGRect iconF; /** * 时间的frame */ @property (nonatomic, assign, readonly) CGRect timeF; /** * 文本信息的frame */ @property (nonatomic, assign, readonly) CGRect textF; /** * cell的高度 */ @property (nonatomic, assign, readonly) CGFloat cellHeight; /** * 数据模型 */ @property (nonatomic, strong) JLMessage *message; @end // // JLMessageFrame.m // 01-QQ // // Created by XinYou on 15-3-3. // Copyright (c) 2015年 vxinyou. All rights reserved. // #import "JLMessageFrame.h" #import "JLMessage.h" #import "NSString+Extension.h" @implementation JLMessageFrame - (void)setMessage:(JLMessage *)message{ // 固定写法 _message = message; // 间距 CGFloat padding = 10; // 屏幕的宽度 CGFloat screenW = [UIScreen mainScreen].bounds.size.width; // 1,时间 if (message.hideTime == NO) {// 显示时间 CGFloat timeX = 0; CGFloat timeY = 0; CGFloat timeW = screenW; CGFloat timeH = 40; _timeF = CGRectMake(timeX, timeY, timeW, timeH); } // 2,头像 CGFloat iconY = CGRectGetMaxY(_timeF) + padding; CGFloat iconW = 40; CGFloat iconH = 40; CGFloat iconX; if (message.type == JLMessageTypeOtherToMe) {// 别人发给自己 iconX = padding; } else {// 自己发给别人 iconX = screenW - padding - iconW; } _iconF = CGRectMake(iconX, iconY, iconW, iconH); // 3,正文 CGFloat textY = iconY; // 文本信息的最大尺寸 CGSize textMaxSize = CGSizeMake(200, MAXFLOAT); // 文本信息的真实尺寸 CGSize textRealSize = [message.text sizeWithFont:JLTextFont maxSize:textMaxSize]; // 按钮最终的真实尺寸(按钮的内部有个Label用于显示文本,默认情况,Lable填充满按钮 // 如果想让Lable中的文字跟按钮有一定的边距。。。) CGSize textBtnSize = CGSizeMake(textRealSize.width + JLTextPadding * 2, textRealSize.height + JLTextPadding * 2); CGFloat textX; if (message.type == JLMessageTypeOtherToMe) {// 别人发给自己 textX = CGRectGetMaxX(_iconF) + padding; }else{ textX = iconX - padding - textBtnSize.width; } // _textF = CGRectMake(textX, textY, textBtnSize.width, textBtnSize.height); _textF = (CGRect){{textX, textY}, textBtnSize};// 两种写法是一样的 // 4,cell的高度 CGFloat textMaxY = CGRectGetMaxY(_textF); CGFloat iconMaxY = CGRectGetMaxY(_iconF); _cellHeight = MAX(textMaxY, iconMaxY) + padding; } @end 
        
       
       
      
      
     
     
    
    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值