赞
踩
最终效果图:
自定义cell的封装
BeyondCell
- //
- // BeyondCell.h
- // 29_仿微信聊天
- //
- // Created by beyond on 14-9-4.
- // Copyright (c) 2014年 com.beyond. All rights reserved.
- //
-
- #import <UIKit/UIKit.h>
- @class BeyondCellFrame;
-
- @interface BeyondCell : UITableViewCell
-
-
- // 一行自定义的cell,初始化的时候,全部生成各个控件并添加到contentView,然后通过cellWithCellFrame方法,将参数CellFrame(内含Msg对象)的所有成员frame和数据 设置到cell中的各个控件上面去
-
-
-
- // 返回xib界面上写的重用cellID
- + (NSString *)cellID;
-
-
- // 通过一个WeiboFrames模型对象(它本身就含有一个Weibo数据 模型),返回一个填充好数据的cell对象
- - (BeyondCell *)cellWithCellFrame:(BeyondCellFrame *)cellFrame;
-
- @end
- //
- // BeyondCell.m
- // 29_仿微信聊天
- //
- // Created by beyond on 14-9-4.
- // Copyright (c) 2014年 com.beyond. All rights reserved.
- //
-
- #import "BeyondCell.h"
- #import "BeyondCellFrame.h"
- #import "Msg.h"
-
- // 类扩展,又叫匿名分类
- @interface BeyondCell()
- {
- // 1,头像
- UIImageView *_headImg;
- // 2,正文内容
- UILabel *_content;
- // 3,大图片
- UIImageView *_bgImg;
- }
- @end
- @implementation BeyondCell
- // 返回xib界面上写的重用cellID
- + (NSString *)cellID
- {
- return @"BeyondCell";
- }
-
- // 当池中没有Cell的时候,创建出一个纯洁的Cell,一次性alloc 出所有的各个子控件 ,并加到contentView
- - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
- {
- self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
- if (self) {
-
- //选中cell后背景无颜色
- self.selectionStyle = UITableViewCellSelectionStyleNone;
- self.backgroundColor = [UIColor clearColor];
-
-
-
- // 不管三七二十一,先把所有的控件实例化,并添加到contentView里面
- // 1,头像
- _headImg = [[UIImageView alloc]init];
- _headImg.layer.cornerRadius = 10;
- _headImg.layer.masksToBounds = YES;
- [self.contentView addSubview:_headImg];
-
-
-
-
-
- // 2,大图片
- _bgImg = [[UIImageView alloc]init];
- [self.contentView addSubview:_bgImg];
-
-
- // 3,正文内容,添加大背景图片里面
- _content = [[UILabel alloc]init];
- _content.backgroundColor = [UIColor clearColor];
-
- // 正文内容用的字体,宏定义在.h
- _content.font = kContentFnt;
- _content.numberOfLines = 0;
- _content.lineBreakMode = NSLineBreakByWordWrapping;
- [_bgImg addSubview:_content];
-
-
- }
- return self;
- }
-
-
- // 通过一个Frames模型对象(它本身就含有一个数据 模型),返回一个填充好数据的cell对象,将参数Frames(内含对象)的所有成员frames和数据 设置到cell中的各个控件上面去
- - (BeyondCell *)cellWithCellFrame:(BeyondCellFrame *)cellFrame
- {
- Msg *msg = cellFrame.msg;
-
-
- // 将模型对象中的所有属性值,全部赋值到cell对象中的成员控件上显示
- // 1,头像
-
-
-
- if ([msg.name isEqualToString:@"nana"]) {
- _headImg.image = [UIImage imageNamed:@"icon01.jpg"];
- } else {
- _headImg.image = [UIImage imageNamed:@"icon02.jpg"];
- }
-
-
- // 5,正文内容
- _content.text = msg.content;
-
- // 6,大图片
- if ([msg.name isEqualToString:@"nana"]) {
- _bgImg.image = [UIImage imageStretchedWithName:@"chatfrom_bg_normal.png" xPos:0.5 yPos:0.6];
-
- } else {
- _bgImg.image = [UIImage
- imageStretchedWithName:@"chatto_bg_normal.png" xPos:0.5 yPos:0.6];
- }
-
-
-
-
- // 1,头像的frame
- _headImg.frame = cellFrame.headImgFrame;
-
-
-
-
- // 2,正文的frame
- _content.frame = cellFrame.contentFrame;
-
- // 3,bigImg的frame
- _bgImg.frame = cellFrame.contentBgImgFrame;
-
-
-
-
-
-
- return self;
- }
-
- @end
封装的数据源Model
- //
- // Msg.h
- // 29_仿微信聊天
- //
- // Created by beyond on 14-9-4.
- // Copyright (c) 2014年 com.beyond. All rights reserved.
- // 模型,成员:icon,正文text
-
- #import <Foundation/Foundation.h>
-
- // 内容 用的字体
- #define kContentFnt [UIFont fontWithName:@"HelveticaNeue" size:18.0f]
-
- @interface Msg : NSObject
- // 头像图片名
- @property (nonatomic,copy) NSString *headImg;
-
-
- // 消息内容
- @property (nonatomic,copy) NSString *content;
-
- @property (nonatomic,copy) NSString *name;
-
- @property (nonatomic,strong) NSString *recordFileFath;
-
- // 类方法,字典 转 对象 类似javaBean一次性填充
- + (Msg *)msgWithDict:(NSDictionary *)dict;
- // 对象方法,设置对象的属性后,返回对象
- - (Msg *)initWithDict:(NSDictionary *)dict;
-
- + (Msg*)msgWithName:(NSString *)name content:(NSString *)content recordFilePath:(NSString *)path;
- @end
- //
- // Msg.m
- // 29_仿微信聊天
- //
- // Created by beyond on 14-9-4.
- // Copyright (c) 2014年 com.beyond. All rights reserved.
- //
-
- #import "Msg.h"
-
- @implementation Msg
-
- // 类方法,字典 转 对象 类似javaBean一次性填充
- + (Msg *)msgWithDict:(NSDictionary *)dict
- {
- return [[self alloc]initWithDict:dict];
- }
-
- // 对象方法,设置对象的属性后,返回对象
- - (Msg *)initWithDict:(NSDictionary *)dict
- {
- // 必须先调用父类NSObject的init方法
- if (self = [super init]) {
- // 设置对象自己的属性
- // 通过遍历 将 字典 赋值为对象各个属性
- for (NSString *key in dict) {
- [self setValue:dict[key] forKeyPath:key];
- }
- // 一次性 将 字典 赋值为对象各个属性
- // [self setValuesForKeysWithDictionary:dict];
-
- }
- // 返回填充好的对象
- return self;
- }
-
- + (Msg*)msgWithName:(NSString *)name content:(NSString *)content recordFilePath:(NSString *)path
- {
- Msg *msg = [[self alloc]init];
- msg.name = name;
- msg.content = content;
- msg.recordFileFath = path;
-
- return msg;
- }
-
- @end
重点:根据数据源计算frame
- //
- // BeyondCellFrame.h
- // 29_仿微信聊天
- //
- // Created by beyond on 14-9-4.
- // Copyright (c) 2014年 com.beyond. All rights reserved.
- //
-
- #import <Foundation/Foundation.h>
- @class Msg;
- // 控件与控件之间的外边距
- #define kMargin 7
- // 头像的高宽
- #define kHeadImgHW 85
-
-
- @interface BeyondCellFrame : NSObject
-
- // 最大的Y值,就是行高
- @property (nonatomic,assign,readonly) CGFloat maxY;
-
- // 重要,拥有一个成员:对象,目的是在控制器中,传递对象进来之后,可以通过此模型对象的数据,计算出所有的frames
- @property (nonatomic,strong) Msg *msg;
-
-
-
- // 头像 的frame
- @property (nonatomic,assign,readonly) CGRect headImgFrame;
-
- // 聊天正文的背景图片 的frame
- @property (nonatomic,assign,readonly) CGRect contentBgImgFrame;
-
- // 正文内容 的frame
- @property (nonatomic,assign,readonly) CGRect contentFrame;
-
-
-
-
- @end
- //
- // BeyondCellFrame.m
- // 29_仿微信聊天
- //
- // Created by beyond on 14-9-4.
- // Copyright (c) 2014年 com.beyond. All rights reserved.
- //
-
- #import "BeyondCellFrame.h"
- #import "Msg.h"
- @implementation BeyondCellFrame
-
-
-
- // CellFrame类 唯一的一个方法:设置Msg的时候,可以通过其数据,计算出各个frame,以及最大的Y,也就是行高
- - (void)setMsg:(Msg *)msg
- {
- _msg = msg;
-
- // 具体的计算各个frame的代码,放在这儿~~~
-
- if ([msg.name isEqualToString:@"nana"]) {
- [self standLeft:msg];
- } else {
- [self standRight:msg];
- }
-
-
- }
- // 我说的放在右边
- - (void)standRight:(Msg *)msg
- {
- // 1,头像的frame
- // 头像的x
- CGFloat headImgX = 320 - kHeadImgHW - kMargin;
- // 头像的y
- CGFloat headImgY = 0;
- // 头像的H
- CGFloat headImgH = kHeadImgHW;
- // 头像的W
- CGFloat headImgW = kHeadImgHW;
- _headImgFrame = CGRectMake(headImgX, headImgY, headImgH, headImgW);
-
-
- //===============****************=======================
-
- // 2,bg的frame
- // 宽度W
- CGFloat bgW = 320 - kHeadImgHW - kMargin;
- // x
- CGFloat bgX = 320 - bgW - kHeadImgHW - kMargin;
- // y
- CGFloat bgY = 0;
-
- // CGFloat winWidth = [[UIApplication sharedApplication] statusBarFrame].size.width;
-
- // 高度先假设 H
- CGFloat bgH = 300;
- _contentBgImgFrame = CGRectMake(bgX, bgY, bgW,bgH);
-
-
- //===============****************=======================
-
- // 3,正文的frame 正文添加到图片里面,以图片的左上角为 0 0
- // x
- CGFloat contentX = kMargin*1.5;
- // y
- CGFloat contentY = kMargin;
-
-
- // 宽度W 先假设大于一行
- CGFloat contentW = bgW - contentX - kMargin ;
- CGFloat contentH = 0;
-
- // 判断 内容够不够一行...
- // 根据字体得到NSString的尺寸
- CGSize oneLineSize = [msg.content sizeWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:kContentFnt,NSFontAttributeName, nil]];
- CGFloat oneLineW = oneLineSize.width;
-
- if (oneLineW < contentW) {
- // 如果不够一行
- CGFloat oneLineH = oneLineSize.height;
- contentX = kMargin * 1.2;
- _contentFrame = CGRectMake(contentX, contentY, oneLineW,oneLineH);
-
- contentH = oneLineH;
- contentW = oneLineW;
-
- // 5,重新调整 contentBgImg的frame的高度
- // 以下三步为OC标准代码,因为OC中不允许直接修该对象中结构体属性的成员的值,要通过中间的临时结构体变量
- CGRect frame = _contentBgImgFrame;
- frame.size.width = contentW + kMargin *3.5;
- frame.size.height = contentH + kMargin * 3 ;
- frame.origin.x = 320 - contentW - headImgW - kMargin*4;
- _contentBgImgFrame = frame;
-
- } else {
- // 如果超过一行,按下面算法计算 高度
- // 根据内容动态设置 高度
- CGRect tmpRect = [msg.content boundingRectWithSize:CGSizeMake(contentW, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:[NSDictionary dictionaryWithObjectsAndKeys:kContentFnt,NSFontAttributeName, nil] context:nil];
- // 高度H
- contentH = tmpRect.size.height;
- _contentFrame = CGRectMake(contentX, contentY, contentW,contentH);
-
- // 5,重新调整 contentBgImg的frame的高度
- // 以下三步为OC标准代码,因为OC中不允许直接修该对象中结构体属性的成员的值,要通过中间的临时结构体变量
- CGRect frame = _contentBgImgFrame;
- frame.size.height = contentH + kMargin * 3 ;
- _contentBgImgFrame = frame;
- }
-
-
- // 8,这个时候就可以计算最大Y 即行高了
- if (headImgH > _contentBgImgFrame.size.height) {
- _maxY = CGRectGetMaxY(_headImgFrame) + kMargin;
- } else {
- _maxY = CGRectGetMaxY(_contentBgImgFrame) + kMargin;
- }
- }
-
- - (void)standLeft:(Msg *)msg
- {
- // 1,头像的frame
- // 头像的x
- CGFloat headImgX = kMargin;
- // 头像的y
- CGFloat headImgY = kMargin;
- // 头像的H
- CGFloat headImgH = kHeadImgHW;
- // 头像的W
- CGFloat headImgW = kHeadImgHW;
- _headImgFrame = CGRectMake(headImgX, headImgY, headImgH, headImgW);
-
-
- //===============****************=======================
-
- // 4,bg的frame
- // x
- CGFloat bgX = _headImgFrame.size.width + kMargin;
- // y
- CGFloat bgY = _headImgFrame.origin.y;
-
- // CGFloat winWidth = [[UIApplication sharedApplication] statusBarFrame].size.width;
-
- // 宽度W
- CGFloat bgW = 320 - bgX - kMargin;
-
-
-
- // 高度H
- CGFloat bgH = 300;
- _contentBgImgFrame = CGRectMake(bgX, bgY, bgW,bgH);
-
-
-
-
-
- // 4,正文的frame 正文添加到图片里面,以图片的左上角为 0 0
- // x
- CGFloat contentX = kMargin*3;
- // y
- CGFloat contentY = kMargin;
-
- // CGFloat winWidth = [[UIApplication sharedApplication] statusBarFrame].size.width;
-
- // 宽度W 先假设大于一行
- CGFloat contentW = bgW - contentX - kMargin ;
- CGFloat contentH = 0;
-
- // 判断 内容够不够一行...
- // 根据字体得到NSString的尺寸
- CGSize oneLineSize = [msg.content sizeWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:kContentFnt,NSFontAttributeName, nil]];
- CGFloat oneLineW = oneLineSize.width;
-
- if (oneLineW < contentW) {
- // 如果不够一行
- CGFloat oneLineH = oneLineSize.height;
- contentX = kMargin * 2;
- _contentFrame = CGRectMake(contentX, contentY, oneLineW,oneLineH);
-
- contentH = oneLineH;
- contentW = oneLineW;
-
- // 5,重新调整 contentBgImg的frame的高度
- // 以下三步为OC标准代码,因为OC中不允许直接修该对象中结构体属性的成员的值,要通过中间的临时结构体变量
- CGRect frame = _contentBgImgFrame;
- frame.size.width = contentW + kMargin *3.5;
- frame.size.height = contentH + kMargin * 3 ;
- _contentBgImgFrame = frame;
-
- } else {
- // 如果超过一行,按下面算法计算 高度
- // 根据内容动态设置 高度
- CGRect tmpRect = [msg.content boundingRectWithSize:CGSizeMake(contentW, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:[NSDictionary dictionaryWithObjectsAndKeys:kContentFnt,NSFontAttributeName, nil] context:nil];
- // 高度H
- contentH = tmpRect.size.height;
- _contentFrame = CGRectMake(contentX, contentY, contentW,contentH);
-
- // 5,重新调整 contentBgImg的frame的高度
- // 以下三步为OC标准代码,因为OC中不允许直接修该对象中结构体属性的成员的值,要通过中间的临时结构体变量
- CGRect frame = _contentBgImgFrame;
- frame.size.height = contentH + kMargin * 3 ;
- _contentBgImgFrame = frame;
- }
-
-
- // 8,这个时候就可以计算最大Y 即行高了
- if (headImgH > _contentBgImgFrame.size.height) {
- _maxY = CGRectGetMaxY(_headImgFrame) + kMargin;
- } else {
- _maxY = CGRectGetMaxY(_contentBgImgFrame) + kMargin;
- }
- }
- @end
控制器
- //
- // BeyondViewController.m
- // 29_仿微信聊天
- //
- // Created by beyond on 14-9-2.
- // Copyright (c) 2014年 com.beyond. All rights reserved.
- //
-
- #import "BeyondViewController.h"
- #import "Msg.h"
- #import "BeyondCellFrame.h"
- #import "BeyondCell.h"
-
- @interface BeyondViewController ()
- {
- // 从plist文件中加载的所有weiboFrames(因为它已经含有一个weibo成员),返回所有的对象组成的数组
- NSMutableArray *_msgFrames;
- }
- @end
-
- @implementation BeyondViewController
-
-
-
-
-
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- // 初始化 对象数组
- _msgFrames = [NSMutableArray array];
- }
-
- #pragma mark - UITextField代理,发送请求
- - (BOOL)textFieldShouldReturn:(UITextField *)textField
- {
-
- if (textField.text.length == 0){
- return NO;
- }
-
-
-
- BeyondCellFrame *frame = [[BeyondCellFrame alloc]init];
- // ***********设置的WeiboFrames的成员weibo的同时,进行了复杂的计算,并填充了WeiboFrames各个frame成员
- frame.msg = [Msg msgWithName:@"jackey" content:textField.text recordFilePath:@"NoRecord"];
- // 添加到对象数组
- [_msgFrames addObject:frame];
- [self.tableView reloadData];
- return YES;
- }
-
- #pragma mark - UITableView代理方法
- - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- {
- //去除cell间隔线
- tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
-
- // 返回对象数组的长度
- return _msgFrames.count;
- }
- // 生成自定义的cell,并传递cellFrame给它,设置好后,返回cell
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- // 1,从池中取
- BeyondCell *cell = [tableView dequeueReusableCellWithIdentifier:[BeyondCell cellID]];
- // 2,取不到的时候,创建一个纯洁的WeiboCell
- if (cell == nil) {
- cell = [[BeyondCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:[BeyondCell cellID]];
- }
- // 3,设置独一无二的数据
- BeyondCellFrame *frame = [_msgFrames objectAtIndex:indexPath.row];
- cell = [cell cellWithCellFrame:frame];
- return cell;
- }
- // cellFrame对象数组有每一行的行高,其内部已经计算好了
- - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
- {
-
- // cellFrame的成员有:Msg数据模型对象,以及根据数据模型计算出来的所有的frames,以及最大的Y即对应数据模型的行高
- BeyondCellFrame *frame = [_msgFrames objectAtIndex:indexPath.row];
- return frame.maxY;
- }
-
- // 恢复view全屏,并且让键盘退出
- - (void)exitKeyboard
- {
- [UIView animateWithDuration:0.2 animations:^{
- self.view.frame = CGRectMake(0, 0, self.view.frame.size.width, [[UIScreen mainScreen]bounds].size.height);
-
- }completion:^(BOOL finished){}];
- [_chatInput resignFirstResponder];
- }
- // 滚至表格最后一行
- - (void)scrollToLastCell;
- {
- if (_msgFrames.count >1) {
- [self.chatTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:_msgFrames.count-1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。