關情紙尾-----UIKit基礎--QQ自定義布心佈局

 

簡述整個項目的開發過程數組

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

  2.建立模型,一個是數據模型,一個是frame模型ide

  3.實現對cell操做的封裝字體

  4.解決顯示時間的細節問題動畫

  5.解決聊天內容的背景問題atom

  6.用通知機制監聽鍵盤spa

  7.發送消息代理

 

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

 

2、建立模型,一個是數據模型,一個是frame模型orm

根據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;
}

 

 

3、實現對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

 

 

 

4、解決顯示時間的細節問題

 若是時間是同樣的,就只顯示一個時間

在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.

 

 5、解決聊天內容的背景問題

//設置圖片

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};
    

 

 

6、用通知機制監聽鍵盤

首先介紹一下通知機制

 

 

 

 

 

 

 

代碼以下:

 

// 監聽鍵盤的通知
    [[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];
}

 

 

 

最終界面如圖:

 

 

學的不精,筆記作的很差,見諒見諒。。。。。。。

相關文章
相關標籤/搜索