关情纸尾-----UIKit基础--QQ自定义布心布局
?
簡述整個項目的開發過程
? 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";//先從緩存池中取cellZLMessageCell *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.取得鍵盤最后的frameCGRect 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.設置文本框左邊顯示的viewself.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:56msg.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]; }?
?
?
最終界面如圖:
?
?
學的不精,筆記做的不好,見諒見諒。。。。。。。
?
轉載于:https://www.cnblogs.com/Lorraine1/p/5766054.html
總結
以上是生活随笔為你收集整理的关情纸尾-----UIKit基础--QQ自定义布心布局的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 函数mod(a,m)
- 下一篇: 帕秋莉·诺蕾姬 (Standard IO