1、搭建UI界面
1.在普通視圖控制器中放一個TableView
2.拖一個UIView,做爲底部工具條
3.在UIView上放一個imageView,換成純白色背景。而後在UIView上放一個按鈕
4.將按鈕的image屬性換成語音圖標,高度寬度均爲44。x,y爲0.(注意不要把背景圖
片屬性換成語音圖標,會被拉伸。),同理再拖2個按鈕換成相應圖標
5.拖一個文本輸入框,將其背景圖片屬性設置爲相應的圖片。數組
2、往TableView中放數據
1.設置數據源
2.新建一個模型MJMessage(plist裏有3個屬性,因此添加3條屬性)ide
typedef enum { MJMessageTypeMe = 0, //本身發的 MJMessageTypeOther // 別人發的 } MJMessageType; //聊天內容 @property (nonatomic,copy)NSString *text; //消息發送時間 @property (nonatomic,copy)NSString *time; //發送者 @property (nonatomic,copy)MJMessageType *type; //是否顯示時間 @property (nonatomic,assign)BOOL hideTime ; //提供字典轉模型的方法,並實現。 +(instancetype)messageWithDict:(NSDictionary *)dict; -(instancetype)initWithDict:(NSDictionary *)dict; +(instancetype)messageWithDict:(NSDictionary *)dict { return [[self alloc] initWithDict:dict]; } -(instancetype)initWithDict:(NSDictionary *)dict { if(self = [super init]) { [self setValuesForKeysWithDictionary:dict]; } return self; }
3.加載模型數據工具
@property(nonatomic,strong)NSMutableArray *messageFrames; -(NSMutableArray *)messageFrames { if(_messageFrames == nil){ //從plist裏面加載出來字典數組 NSArray *dictArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"nessages.plist" ofType:nil]]; NSMutbleArray *msgArray = [NSMutableArray array]; // 將字典轉成message模型 for (NSDictionary *dict in dictArray) { //消息模型 MJMessage *msg = [MJMessage messageWithDict:dict]; //取出上一個模型 MJMessageFrame *lastMf = [mfArray lastObejct]; MJMessage *lastMsg = lastMf.message; //判斷兩個消息的時間是否一致 msg.hideTime = [msg.time isEqualToString:lastMsg.time]; //frame模型 MJMessageFrame *mf = [MJMessageFrame alloc] init]; mf.message = msg; //添加 [mfArray addObejct:mf]; } _messageFrames = mfArray; } return _messageFrames; }
4.遵照協議並實現數據源方法字體
第一個數據源方法: 由於只有一列因此能夠不實現。默認爲1列 第二個數據源方法: numberOfRowsInSection:方法 return self.messageFrames.count; 第三個數據源方法: cellForRowAtIndexPath:方法 //1.建立cell MJMessageCell *cell = [MJMessageCell cellWithTableView:tableView]; //2.給cell傳遞模型(在算完frame和cell高度以後進行這一步) cell.messageFrame = self.messageFrames[indexPath.row]; //3.返回cell return cell;
5.設置行高(設置代理遵照協議並實現代理方法 heightForRowAtIndexPath:方法)atom
{ MJMessageFrame *mf = self.messageFrames[indexPath.row]; return cellHeight; }
6..經過代碼自定義cell(cell的高度不一致)
1>新建一個Cell類MJMessageCell(注意要提供一個方法快速建立cell)
2>在cell的實現文件中重寫initWithStyle:reuseIndetifier:方法
添加全部須要顯示的子控件(不須要設置子控件的屬性和frame,子控件要添加到contentView中)
進行子控件一次性的屬性設置(有些屬性只須要設置一次,好比字體、固定的圖片)spa
//由於時間,頭像和正文要在其餘方法中使用,因此先將它們聲明爲成員變量 @property (nonatomic,weak)UILabel *timeView; @property (nonatomic,weak)UIImageView *iconView; @property (nonatomic,weak)UIButton *textView; 在這個例子中 //1.時間 UILabel *timeView = [[UILabel alloc] init]; timeView.textAlignment = NSTextAlignmentCenter timeView.textColor = [UIColor lightGrayColor]; timeView.font = [UIFont systemFont: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 = MJTextFont; textView.contextEdgaInsets = UIEdgeInsetsMake(MJTextPadding,MJTextPadding,MJTextPadding,MJTextPadding); [textView setTitleColor:[UIColor blackColor] ForState:UIControlStateNormal]; [self.contentView addSubview:textView]; self.textView = textView; //4.設置cell的背景色 self.backgroundColor = [UIColor clearColor];
3>提供2個模型
數據模型:存放文字數據/圖片數據。已經建立好了,爲MJMessage
frame模型:存放數據模型/全部子控件的frame/cell的高度
新建一個類MJMessageFrame並添加屬性代理
//頭像frame @property(nonatomic,assgin,readonly)CGRect iconF; //事件的frame @property(nonatomic,assgin,readonly)CGRect timeF; //正文的frame @property(nonatomic,assgin,readonly)CGRect textF; //cell的高度 @property(nonatomic,assgin,readonly)CGFloat cellHeight; //數據模型 @class MJMessage; @property(nonatomic,strong)MJMessage *message;
4>cell擁有一個frame模型(不要直接擁有數據模型)
@property(nonatomic,strong)MJMessageFrame *messageFrame;
5>重寫frame模型屬性的setter方法,在這個方法中設置子控件的顯示數據和framecode
-(void)setMessageFrame:(MJMessageFrame *)messageFrame { _messageFrame = messageFrame; MJMessage *message = messageFrame.message; //1.時間 self.timeView.text = message.time; self.timeView.frame = messageFrame.timeF; //2.頭像 NSString *icon = message.type == MJMessageTypeMe ? @"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 == MJMessageTypeMe){ //本身發的(藍色) [self.textView setBackgroundImage:[UIImage resizableImage:@"chat_send_nor"] forState:UIControlStateNormal]; } else { //別人發的(白色) [self.textView setBackgroundImage:[UIImage resizableImage:@"chat_recive_nor"] forState:UIControlStateNormal]; } }
知識點:圖片過小文字放不下怎麼辦-->設置按鈕的內邊距orm
-(void)setMessage:(MJMessage *)message { _message = message; //間距 CGFloat padding = 10; //屏幕的寬度 CGFloat screenW = [UIScreen mainScreen].bounds.width; //1.時間 message.time 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 == MJMessageTypeOther) { //別人發的 iconX = padding; } else { //本身發的 iconX = screenW - padding - iconW; } _iconF = CGRectMake(iconX,iconY,iconW,iconH); //3.正文 CGFloat textY = iconY; //文字計算的最大的尺寸 CGSize textMaxSize = CGSizeMake(150,MAXFLOAT); //文字計算出來的真實尺寸(按鈕內部label的尺寸) CGSize textRealSize = [message.text sizeWithFont:MJTextFont maxSize:textMaxSize]; //按鈕最終的真實尺寸 CGSize textBtnSize = CGSizeMake(textRealSize.width + MJTextPadding * 2,textRealSize.height+ MJTextPadding * 2); CGFloat textX; if(message.type == MJMesageTypeOther) { textX= CGRectGetMaxX(_iconF)+padding; } else { textX = iconX - padding - textBtnSize.width ; } } _textF =(CGRect){{textX,textY}, textBtnSize}; } //4.cell的高度 CGFloat textMaxY = CGRectGetMaxY(_textF); CGFloat iconMaxY = CGRectGetMaxY(_iconF); _cellHeight = MAX(textMaxY,iconMaxY) + padding;
6>frame模型數據的初始化已經採起惰性初始化的方式(每個cell對應的frame模型數據只加載一次) blog
細節:
1.在viewDidLoad中去除分隔線
1>連線拿到tableView
2>self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
2.添加背景色
self.tableView.backgroundColor = [UIColor colorWithRed:224/255.0 green:224/255.0 Blue:224/255.0 alpha:1.0];
3.去掉狀態欄
-(BOOL)prefersStatusBarHidden { return YES; }
4.cell不能被選中
self.tableView.allowsSelection = NO;
3、將實用的功能抽成分類(不必使用類)
分類:給已經存在的類擴展一些方法
1.功能1: 計算文字尺寸
1>新建一個NSString的分類Extension
2>聲明並實現下列方法
/* @param font 文字的字體 @param maxSize 文字的最大尺寸 */ -(CGSzie)sizeWithFont:(UIFont *)font maxSize:(CGSzie)maxSize { NSDictionary *attrs = @[NSFontAttributeName : font ]; return [self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size; }
3>導入分類頭文件便可使用該分類裏的方法。
2.功能二:返回一張能夠隨意拉伸不變形的圖片
1>新建一個UIImage的分類Extension
2>聲明並實現下列方法
+(UIImage *)resizableImage:(NSString *)name { UIImage *normal = [UIImage imageNamed:name]; CGFloat w = normal.size.width * 0.5; CGFloat h = normal.size.height * 0.5; return [normal resizableImageWithCapInsets:UIEdgeInsetsMake(h,w,h,w) ]; }
3>導入分類頭文件便可使用該分類裏的方法。