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>导入分类头文件便可使用该分类里的方法。