码迷,mamicode.com
首页 > 其他好文 > 详细

关情纸尾-----UIKit基础--QQ自定义布心布局

时间:2016-08-12 19:53:44      阅读:224      评论:0      收藏:0      [点我收藏+]

标签:

 

简述整个项目的开发过程

  1.在main.stroybord 中搭建基本界面

  2.创建模型,一个是数据模型,一个是frame模型

  3.实现对cell操作的封装

  4.解决显示时间的细节问题

  5.解决聊天内容的背景问题

  6.用通知机制监听键盘

  7.发送消息

 

一、在main.stroybord 中搭建基本界面

技术分享

 

二、创建模型,一个是数据模型,一个是frame模型

根据message.plist文件创建模型

数据模型ZLMessage

 1 #import <Foundation/Foundation.h>
 2 
 3 
 4 
 5 typedef enum {
 6     ZLMessageTypeMe = 0, //0表示自己,并且系统默认的 也是0 ,然后递增加1
 7     ZLMessageTypeOther
 8 }ZLMessageType;
 9 
10 @interface ZLMessage : NSObject
11 
12 //时间
13 @property (nonatomic, strong) NSString *time;
14 
15 //内容
16 @property (nonatomic, strong)NSString *text;
17 
18 //类型
19 @property (nonatomic, assign)ZLMessageType type;
20 
21 //是否显示时间
22 @property (nonatomic, assign)BOOL hideTime;
23 
24 +(instancetype)messageWithDict:(NSDictionary *)dict;
25 -(instancetype)initWithDict:(NSDictionary *)dict;
26 @end

 

#import "ZLMessage.h"

@implementation ZLMessage


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

    return [[self alloc] initWithDict:dict];
}
-(instancetype)initWithDict:(NSDictionary *)dict{

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

}
@end

 

 

 

frame模型ZLMessageFrame

 

#import <Foundation/Foundation.h>
#import "UIKit/UIkit.h"
@class ZLMessage;

@interface ZLMessageFrame : 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) ZLMessage* message;

@end

#define ZLTextFont [UIFont systemFontOfSize:15]


#import "ZLMessageFrame.h"


#import "ZLMessage.h"

@implementation ZLMessageFrame

/**

 *  计算文字尺寸

 *

 *  @param text    需要计算尺寸的文字

 *  @param font    文字的字体

 *  @param maxSize 文字的最大尺寸

 */


- (CGSize)sizeWithText:(NSString *)text font:(UIFont *)font maxSize:(CGSize)maxSize

{

    NSDictionary *attrs = @{NSFontAttributeName : font};

    return [text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size;

}

-(void)setMessage:(ZLMessage *)message

{    _message = message;

    //计算头像,正文,时间的Frame

    CGFloat sreenW = [UIScreen mainScreen].bounds.size.width;

    CGFloat padding = 10;    

    //1.时间

  CGFloat timeX = 0;

    CGFloat timeY = 0;

    CGFloat timeW = sreenW;

    CGFloat timeH = 40;

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

     //2.头像

    CGFloat iconY = CGRectGetMaxY(_timeF);

    CGFloat iconW = 40;

    CGFloat iconH = 40;

    CGFloat iconX;

    if (message.type == ZLMessageTypeOther) {

        iconX = padding;

    } else {

        iconX = sreenW - iconW - padding;

    }

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

    //3.正文

    CGFloat textY = iconY;

    CGFloat textX;

    //文字的尺寸

    CGSize textMaxSize = CGSizeMake(150, MAXFLOAT);

    CGSize textSize = [self sizeWithText:message.text font:ZLTextFont maxSize:textMaxSize];

    if (message.type == ZLMessageTypeOther) {

        textX = CGRectGetMaxX(_iconF) + padding;

    } else {

        textX = iconX - padding - textSize.width;

    }

    _textF = (CGRect){{textX,textY},textSize};

    //cell 的高度

    CGFloat textMaxY = CGRectGetMaxY(_textF);

    CGFloat iconMaxY = CGRectGetMaxY(_iconF);

   _cellHeight = MAX(textMaxY, iconMaxY) + padding;

}


@end

 
- (NSMutableArray *)messagesFrames
{
    if (_messagesFrames == nil){
        //取出路径
        NSString *path = [[NSBundle mainBundle] pathForResource:@"messages.plist" ofType:nil];
        
        //取出该路劲下的数组
        NSArray *dictArray = [NSArray arrayWithContentsOfFile:path];
        
        NSMutableArray *mfArray = [NSMutableArray array];
        
        //遍历数组形成字典
        for (NSDictionary* dict  in dictArray) {
            //消息模型
            ZLMessage *msg = [ZLMessage messageWithDict:dict];
            
            
            //frame模型
            ZLMessageFrame *mgf =[[ZLMessageFrame alloc] init];
            mgf.message = msg;
            
            [mfArray addObject:mgf];
        }
        _messagesFrames = mfArray;
    }
    
    return _messagesFrames;
}

 

 

三、实现对cell操作的封装

 

#import <UIKit/UIKit.h>

@class ZLMessageFrame;

@interface ZLMessageCell : UITableViewCell

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

@property (nonatomic, strong) ZLMessageFrame* messageFrame;

@end
#define ZLTextFont [UIFont systemFontOfSize:15]
#import "ZLMessageCell.h"
#import "ZLMessageFrame.h"
#import "ZLMessage.h"


@interface ZLMessageCell()
//时间
@property (nonatomic, weak) UILabel *timeView;

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

//正文
@property (nonatomic, weak) UIButton *textView;;

@end

@implementation ZLMessageCell

+(instancetype) cellWithTableView:(UITableView *)tableView
{
    static NSString *ID = @"message";
    //先从缓存池中取cell
    ZLMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:ID ];
    //如果缓存池中没有就自己创建cell,并且要带有标记
    if (cell == nil) {
        cell = [[ZLMessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    }
    return cell;
}

//做一次性的初始化
-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{

    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self){
        
        //子控件的创建和初始化
        //1.时间
        UILabel *timeView = [[UILabel alloc] init];
        timeView.textColor = [UIColor grayColor];
        timeView.textAlignment = NSTextAlignmentCenter;
        timeView.font = [UIFont systemFontOfSize:13];
        [self.contentView addSubview:timeView];
        self.timeView = timeView;
        
        //2.头像
        UIImageView *iconView = [[UIImageView alloc] init];
        //iconView.backgroundColor = [UIColor redColor];
        [self.contentView addSubview:iconView];
        self.iconView = iconView;
        
        //3.正文
        UIButton *textView = [[UIButton alloc] init];
        textView.titleLabel.numberOfLines = 0;//自动换行
        textView.backgroundColor = [UIColor purpleColor];
        textView.titleLabel.font = ZLTextFont;
        [self.contentView addSubview:textView];
        self.textView = textView;
        
    }
    return self;

}

-(void)setMessageFrame:(ZLMessageFrame *)messageFrame
{
    _messageFrame = messageFrame;
    ZLMessage *message = messageFrame.message;
    
    //时间
    self.timeView.text = message.time;
    self.timeView.frame = messageFrame.timeF;
    
    //头像
    NSString *icon = (message.type == ZLMessageTypeMe) ? @"me" : @"other";
    self.iconView.image = [UIImage imageNamed:icon];
    self.iconView.frame = messageFrame.iconF;
    
    
    //正文
    [self.textView setTitle:message.text forState:UIControlStateNormal];
    self.textView.frame = messageFrame.textF;

}
@end

 

 

 

四、解决显示时间的细节问题

 如果时间是一样的,就只显示一个时间

在ZLMessage.h文件中添加属性

//是否显示时间
@property (nonatomic, assign)BOOL hideTime;
在控制器.m文件中添加代码,即取出上一个模型和刚刚添加的模型的时间作比较,如果时间一样,就只显示上一个模型的time数据
//遍历数组形成字典
        for (NSDictionary* dict  in dictArray) {
            //消息模型
            ZLMessage *msg = [ZLMessage messageWithDict:dict];
            
            //取出上一个模型
            ZLMessageFrame *lastMf = [mfArray lastObject];
            ZLMessage *lastMg = lastMf.message;
            
            msg.hideTime = [msg.time isEqualToString:lastMg.

 

 五、解决聊天内容的背景问题

//设置图片

if (message.type == MJMessageTypeMe) { // 自己发的,蓝色
        [self.textView setBackgroundImage:[UIImage resizableImage:@"chat_send_nor"] forState:UIControlStateNormal];
    } else { // 别人发的,白色
        [self.textView setBackgroundImage:[UIImage resizableImage:@"chat_recive_nor"] forState:UIControlStateNormal];
    }
//为了显示对话框背景图,需要设置正文按钮的内边距
        
textView.contentEdgeInsets = UIEdgeInsetsMake(ZLTextPadding, ZLTextPadding, ZLTextPadding, ZLTextPadding);
//文字计算的最大尺寸
    CGSize textMaxSize = CGSizeMake(150, MAXFLOAT);
//文字计算出来的真实尺寸(显示文字的尺寸)
    CGSize textSize = [self sizeWithText:message.text font:ZLTextFont maxSize:textMaxSize];
 //按钮最终的尺寸   
    CGSize textBtnSize = CGSizeMake(textSize.width +ZLTextPadding *2, textSize.height +ZLTextPadding *2);
    
    if (message.type == ZLMessageTypeOther) {
        textX = CGRectGetMaxX(_iconF) + padding;
    } else {
        textX = iconX - padding - textBtnSize.width;
    }
//    _textF = CGRectMake(textX, textY, textSize.width +40, textSize.height +40);
    _textF = (CGRect){{textX,textY},textBtnSize};
    

 

 

六、用通知机制监听键盘

首先介绍一下通知机制

技术分享

 

技术分享

 

技术分享

 

技术分享

 

 

技术分享

 

技术分享

 

代码如下:

 

// 监听键盘的通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];

//取消监听
- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}


/**
 *  当键盘改变了frame(位置和尺寸)的时候调用
 */
- (void)keyboardWillChangeFrame:(NSNotification *)note
{
    // 设置窗口的颜色
    self.view.window.backgroundColor = self.tableView.backgroundColor;
    
    // 0.取出键盘动画的时间
    CGFloat duration = [note.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    
    // 1.取得键盘最后的frame
    CGRect keyboardFrame = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    
    // 2.计算控制器的view需要平移的距离
    CGFloat transformY = keyboardFrame.origin.y - self.view.frame.size.height;
    
    // 3.执行动画
    [UIView animateWithDuration:duration animations:^{
        self.view.transform = CGAffineTransformMakeTranslation(0, transformY);
    }];
}


 

 

7.发送消息

 

//监听文本框

#import "MJViewController.h"
#import "MJMessage.h"
#import "MJMessageFrame.h"
#import "MJMessageCell.h"

@interface MJViewController () <UITableViewDataSource, UITableViewDelegate, UITableViewDelegate, UITextFieldDelegate>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic, strong) NSMutableArray *messageFrames;

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

@property (nonatomic, strong) NSDictionary *autoreply;
@end

@implementation MJViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // 1.表格的设置
    // 去除分割线
    self.tableView.backgroundColor = [UIColor colorWithRed:235/255.0 green:235/255.0 blue:235/255.0 alpha:1.0];
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    self.tableView.allowsSelection = NO; // 不允许选中
    self.tableView.delegate = self;
    // 2.监听键盘的通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
    // 3.设置文本框左边显示的view
    self.inputView.leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 8, 0)];
    // 永远显示
    self.inputView.leftViewMode = UITextFieldViewModeAlways;
    self.inputView.delegate = self;
}
/**
 *  发送一条消息
 */
- (void)addMessage:(NSString *)text type:(MJMessageType)type
{
    // 1.数据模型
    MJMessage *msg = [[MJMessage alloc] init];
    msg.type = type;
    msg.text = text;
    // 设置数据模型的时间
    NSDate *now = [NSDate date];
    NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
    fmt.dateFormat = @"HH:mm";
    // NSDate  --->  NSString
    // NSString ---> NSDate
    //    fmt.dateFormat = @"yyyy-MM-dd HH:mm:ss";
    //  2014-08-09 15:45:56
    // 09/08/2014  15:45:56
    msg.time = [fmt stringFromDate:now];
    
    // 看是否需要隐藏时间
    MJMessageFrame *lastMf = [self.messageFrames lastObject];
    MJMessage *lastMsg = lastMf.message;
    msg.hideTime = [msg.time isEqualToString:lastMsg.time];
    
    // 2.frame模型
    MJMessageFrame *mf = [[MJMessageFrame alloc] init];
    mf.message = msg;
    [self.messageFrames addObject:mf];
    
    // 3.刷新表格
    [self.tableView reloadData];
    
    // 4.自动滚动表格到最后一行
    NSIndexPath *lastPath = [NSIndexPath indexPathForRow:self.messageFrames.count - 1 inSection:0];
    [self.tableView scrollToRowAtIndexPath:lastPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}

/**
 *  根据自己发的内容取得自动回复的内容
 *
 *  @param text 自己发的内容
 */
- (NSString *)replayWithText:(NSString *)text
{
    for (int i = 0; i<text.length; i++) {
        NSString *word = [text substringWithRange:NSMakeRange(i, 1)];
        
        if (self.autoreply[word]) return self.autoreply[word];
    }
    
    return @"滚蛋";
}

#pragma mark - 文本框代理
/**
 *  点击了return按钮(键盘最右下角的按钮)就会调用
 */
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    // 1.自己发一条消息
    [self addMessage:textField.text type:MJMessageTypeMe];
    
    // 2.自动回复一条消息
    NSString *reply = [self replayWithText:textField.text];
    [self addMessage:reply type:MJMessageTypeOther];
    
    // 3.清空文字
    self.inputView.text = nil;
    
    // 返回YES即可
    return YES;
}

/**
 *  当开始拖拽表格的时候就会调用
 */
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    // 退出键盘
    [self.view endEditing:YES];
}

 

 

 

最终界面如图:

技术分享 

 

学的不精,笔记做的不好,见谅见谅。。。。。。。

 

关情纸尾-----UIKit基础--QQ自定义布心布局

标签:

原文地址:http://www.cnblogs.com/Lorraine1/p/5766054.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!