当前位置:   article > 正文

iOS_29仿微信聊天界面_ios 防微信聊天界面

ios 防微信聊天界面

最终效果图:





自定义cell的封装

BeyondCell

  1. //
  2. // BeyondCell.h
  3. // 29_仿微信聊天
  4. //
  5. // Created by beyond on 14-9-4.
  6. // Copyright (c) 2014年 com.beyond. All rights reserved.
  7. //
  8. #import <UIKit/UIKit.h>
  9. @class BeyondCellFrame;
  10. @interface BeyondCell : UITableViewCell
  11. // 一行自定义的cell,初始化的时候,全部生成各个控件并添加到contentView,然后通过cellWithCellFrame方法,将参数CellFrame(内含Msg对象)的所有成员frame和数据 设置到cell中的各个控件上面去
  12. // 返回xib界面上写的重用cellID
  13. + (NSString *)cellID;
  14. // 通过一个WeiboFrames模型对象(它本身就含有一个Weibo数据 模型),返回一个填充好数据的cell对象
  15. - (BeyondCell *)cellWithCellFrame:(BeyondCellFrame *)cellFrame;
  16. @end

  1. //
  2. // BeyondCell.m
  3. // 29_仿微信聊天
  4. //
  5. // Created by beyond on 14-9-4.
  6. // Copyright (c) 2014年 com.beyond. All rights reserved.
  7. //
  8. #import "BeyondCell.h"
  9. #import "BeyondCellFrame.h"
  10. #import "Msg.h"
  11. // 类扩展,又叫匿名分类
  12. @interface BeyondCell()
  13. {
  14. // 1,头像
  15. UIImageView *_headImg;
  16. // 2,正文内容
  17. UILabel *_content;
  18. // 3,大图片
  19. UIImageView *_bgImg;
  20. }
  21. @end
  22. @implementation BeyondCell
  23. // 返回xib界面上写的重用cellID
  24. + (NSString *)cellID
  25. {
  26. return @"BeyondCell";
  27. }
  28. // 当池中没有Cell的时候,创建出一个纯洁的Cell,一次性alloc 出所有的各个子控件 ,并加到contentView
  29. - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
  30. {
  31. self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
  32. if (self) {
  33. //选中cell后背景无颜色
  34. self.selectionStyle = UITableViewCellSelectionStyleNone;
  35. self.backgroundColor = [UIColor clearColor];
  36. // 不管三七二十一,先把所有的控件实例化,并添加到contentView里面
  37. // 1,头像
  38. _headImg = [[UIImageView alloc]init];
  39. _headImg.layer.cornerRadius = 10;
  40. _headImg.layer.masksToBounds = YES;
  41. [self.contentView addSubview:_headImg];
  42. // 2,大图片
  43. _bgImg = [[UIImageView alloc]init];
  44. [self.contentView addSubview:_bgImg];
  45. // 3,正文内容,添加大背景图片里面
  46. _content = [[UILabel alloc]init];
  47. _content.backgroundColor = [UIColor clearColor];
  48. // 正文内容用的字体,宏定义在.h
  49. _content.font = kContentFnt;
  50. _content.numberOfLines = 0;
  51. _content.lineBreakMode = NSLineBreakByWordWrapping;
  52. [_bgImg addSubview:_content];
  53. }
  54. return self;
  55. }
  56. // 通过一个Frames模型对象(它本身就含有一个数据 模型),返回一个填充好数据的cell对象,将参数Frames(内含对象)的所有成员frames和数据 设置到cell中的各个控件上面去
  57. - (BeyondCell *)cellWithCellFrame:(BeyondCellFrame *)cellFrame
  58. {
  59. Msg *msg = cellFrame.msg;
  60. // 将模型对象中的所有属性值,全部赋值到cell对象中的成员控件上显示
  61. // 1,头像
  62. if ([msg.name isEqualToString:@"nana"]) {
  63. _headImg.image = [UIImage imageNamed:@"icon01.jpg"];
  64. } else {
  65. _headImg.image = [UIImage imageNamed:@"icon02.jpg"];
  66. }
  67. // 5,正文内容
  68. _content.text = msg.content;
  69. // 6,大图片
  70. if ([msg.name isEqualToString:@"nana"]) {
  71. _bgImg.image = [UIImage imageStretchedWithName:@"chatfrom_bg_normal.png" xPos:0.5 yPos:0.6];
  72. } else {
  73. _bgImg.image = [UIImage
  74. imageStretchedWithName:@"chatto_bg_normal.png" xPos:0.5 yPos:0.6];
  75. }
  76. // 1,头像的frame
  77. _headImg.frame = cellFrame.headImgFrame;
  78. // 2,正文的frame
  79. _content.frame = cellFrame.contentFrame;
  80. // 3,bigImg的frame
  81. _bgImg.frame = cellFrame.contentBgImgFrame;
  82. return self;
  83. }
  84. @end


封装的数据源Model

  1. //
  2. // Msg.h
  3. // 29_仿微信聊天
  4. //
  5. // Created by beyond on 14-9-4.
  6. // Copyright (c) 2014年 com.beyond. All rights reserved.
  7. // 模型,成员:icon,正文text
  8. #import <Foundation/Foundation.h>
  9. // 内容 用的字体
  10. #define kContentFnt [UIFont fontWithName:@"HelveticaNeue" size:18.0f]
  11. @interface Msg : NSObject
  12. // 头像图片名
  13. @property (nonatomic,copy) NSString *headImg;
  14. // 消息内容
  15. @property (nonatomic,copy) NSString *content;
  16. @property (nonatomic,copy) NSString *name;
  17. @property (nonatomic,strong) NSString *recordFileFath;
  18. // 类方法,字典 转 对象 类似javaBean一次性填充
  19. + (Msg *)msgWithDict:(NSDictionary *)dict;
  20. // 对象方法,设置对象的属性后,返回对象
  21. - (Msg *)initWithDict:(NSDictionary *)dict;
  22. + (Msg*)msgWithName:(NSString *)name content:(NSString *)content recordFilePath:(NSString *)path;
  23. @end


  1. //
  2. // Msg.m
  3. // 29_仿微信聊天
  4. //
  5. // Created by beyond on 14-9-4.
  6. // Copyright (c) 2014年 com.beyond. All rights reserved.
  7. //
  8. #import "Msg.h"
  9. @implementation Msg
  10. // 类方法,字典 转 对象 类似javaBean一次性填充
  11. + (Msg *)msgWithDict:(NSDictionary *)dict
  12. {
  13. return [[self alloc]initWithDict:dict];
  14. }
  15. // 对象方法,设置对象的属性后,返回对象
  16. - (Msg *)initWithDict:(NSDictionary *)dict
  17. {
  18. // 必须先调用父类NSObject的init方法
  19. if (self = [super init]) {
  20. // 设置对象自己的属性
  21. // 通过遍历 将 字典 赋值为对象各个属性
  22. for (NSString *key in dict) {
  23. [self setValue:dict[key] forKeyPath:key];
  24. }
  25. // 一次性 将 字典 赋值为对象各个属性
  26. // [self setValuesForKeysWithDictionary:dict];
  27. }
  28. // 返回填充好的对象
  29. return self;
  30. }
  31. + (Msg*)msgWithName:(NSString *)name content:(NSString *)content recordFilePath:(NSString *)path
  32. {
  33. Msg *msg = [[self alloc]init];
  34. msg.name = name;
  35. msg.content = content;
  36. msg.recordFileFath = path;
  37. return msg;
  38. }
  39. @end


重点:根据数据源计算frame


  1. //
  2. // BeyondCellFrame.h
  3. // 29_仿微信聊天
  4. //
  5. // Created by beyond on 14-9-4.
  6. // Copyright (c) 2014年 com.beyond. All rights reserved.
  7. //
  8. #import <Foundation/Foundation.h>
  9. @class Msg;
  10. // 控件与控件之间的外边距
  11. #define kMargin 7
  12. // 头像的高宽
  13. #define kHeadImgHW 85
  14. @interface BeyondCellFrame : NSObject
  15. // 最大的Y值,就是行高
  16. @property (nonatomic,assign,readonly) CGFloat maxY;
  17. // 重要,拥有一个成员:对象,目的是在控制器中,传递对象进来之后,可以通过此模型对象的数据,计算出所有的frames
  18. @property (nonatomic,strong) Msg *msg;
  19. // 头像 的frame
  20. @property (nonatomic,assign,readonly) CGRect headImgFrame;
  21. // 聊天正文的背景图片 的frame
  22. @property (nonatomic,assign,readonly) CGRect contentBgImgFrame;
  23. // 正文内容 的frame
  24. @property (nonatomic,assign,readonly) CGRect contentFrame;
  25. @end


  1. //
  2. // BeyondCellFrame.m
  3. // 29_仿微信聊天
  4. //
  5. // Created by beyond on 14-9-4.
  6. // Copyright (c) 2014年 com.beyond. All rights reserved.
  7. //
  8. #import "BeyondCellFrame.h"
  9. #import "Msg.h"
  10. @implementation BeyondCellFrame
  11. // CellFrame类 唯一的一个方法:设置Msg的时候,可以通过其数据,计算出各个frame,以及最大的Y,也就是行高
  12. - (void)setMsg:(Msg *)msg
  13. {
  14. _msg = msg;
  15. // 具体的计算各个frame的代码,放在这儿~~~
  16. if ([msg.name isEqualToString:@"nana"]) {
  17. [self standLeft:msg];
  18. } else {
  19. [self standRight:msg];
  20. }
  21. }
  22. // 我说的放在右边
  23. - (void)standRight:(Msg *)msg
  24. {
  25. // 1,头像的frame
  26. // 头像的x
  27. CGFloat headImgX = 320 - kHeadImgHW - kMargin;
  28. // 头像的y
  29. CGFloat headImgY = 0;
  30. // 头像的H
  31. CGFloat headImgH = kHeadImgHW;
  32. // 头像的W
  33. CGFloat headImgW = kHeadImgHW;
  34. _headImgFrame = CGRectMake(headImgX, headImgY, headImgH, headImgW);
  35. //===============****************=======================
  36. // 2,bg的frame
  37. // 宽度W
  38. CGFloat bgW = 320 - kHeadImgHW - kMargin;
  39. // x
  40. CGFloat bgX = 320 - bgW - kHeadImgHW - kMargin;
  41. // y
  42. CGFloat bgY = 0;
  43. // CGFloat winWidth = [[UIApplication sharedApplication] statusBarFrame].size.width;
  44. // 高度先假设 H
  45. CGFloat bgH = 300;
  46. _contentBgImgFrame = CGRectMake(bgX, bgY, bgW,bgH);
  47. //===============****************=======================
  48. // 3,正文的frame 正文添加到图片里面,以图片的左上角为 0 0
  49. // x
  50. CGFloat contentX = kMargin*1.5;
  51. // y
  52. CGFloat contentY = kMargin;
  53. // 宽度W 先假设大于一行
  54. CGFloat contentW = bgW - contentX - kMargin ;
  55. CGFloat contentH = 0;
  56. // 判断 内容够不够一行...
  57. // 根据字体得到NSString的尺寸
  58. CGSize oneLineSize = [msg.content sizeWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:kContentFnt,NSFontAttributeName, nil]];
  59. CGFloat oneLineW = oneLineSize.width;
  60. if (oneLineW < contentW) {
  61. // 如果不够一行
  62. CGFloat oneLineH = oneLineSize.height;
  63. contentX = kMargin * 1.2;
  64. _contentFrame = CGRectMake(contentX, contentY, oneLineW,oneLineH);
  65. contentH = oneLineH;
  66. contentW = oneLineW;
  67. // 5,重新调整 contentBgImg的frame的高度
  68. // 以下三步为OC标准代码,因为OC中不允许直接修该对象中结构体属性的成员的值,要通过中间的临时结构体变量
  69. CGRect frame = _contentBgImgFrame;
  70. frame.size.width = contentW + kMargin *3.5;
  71. frame.size.height = contentH + kMargin * 3 ;
  72. frame.origin.x = 320 - contentW - headImgW - kMargin*4;
  73. _contentBgImgFrame = frame;
  74. } else {
  75. // 如果超过一行,按下面算法计算 高度
  76. // 根据内容动态设置 高度
  77. CGRect tmpRect = [msg.content boundingRectWithSize:CGSizeMake(contentW, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:[NSDictionary dictionaryWithObjectsAndKeys:kContentFnt,NSFontAttributeName, nil] context:nil];
  78. // 高度H
  79. contentH = tmpRect.size.height;
  80. _contentFrame = CGRectMake(contentX, contentY, contentW,contentH);
  81. // 5,重新调整 contentBgImg的frame的高度
  82. // 以下三步为OC标准代码,因为OC中不允许直接修该对象中结构体属性的成员的值,要通过中间的临时结构体变量
  83. CGRect frame = _contentBgImgFrame;
  84. frame.size.height = contentH + kMargin * 3 ;
  85. _contentBgImgFrame = frame;
  86. }
  87. // 8,这个时候就可以计算最大Y 即行高了
  88. if (headImgH > _contentBgImgFrame.size.height) {
  89. _maxY = CGRectGetMaxY(_headImgFrame) + kMargin;
  90. } else {
  91. _maxY = CGRectGetMaxY(_contentBgImgFrame) + kMargin;
  92. }
  93. }
  94. - (void)standLeft:(Msg *)msg
  95. {
  96. // 1,头像的frame
  97. // 头像的x
  98. CGFloat headImgX = kMargin;
  99. // 头像的y
  100. CGFloat headImgY = kMargin;
  101. // 头像的H
  102. CGFloat headImgH = kHeadImgHW;
  103. // 头像的W
  104. CGFloat headImgW = kHeadImgHW;
  105. _headImgFrame = CGRectMake(headImgX, headImgY, headImgH, headImgW);
  106. //===============****************=======================
  107. // 4,bg的frame
  108. // x
  109. CGFloat bgX = _headImgFrame.size.width + kMargin;
  110. // y
  111. CGFloat bgY = _headImgFrame.origin.y;
  112. // CGFloat winWidth = [[UIApplication sharedApplication] statusBarFrame].size.width;
  113. // 宽度W
  114. CGFloat bgW = 320 - bgX - kMargin;
  115. // 高度H
  116. CGFloat bgH = 300;
  117. _contentBgImgFrame = CGRectMake(bgX, bgY, bgW,bgH);
  118. // 4,正文的frame 正文添加到图片里面,以图片的左上角为 0 0
  119. // x
  120. CGFloat contentX = kMargin*3;
  121. // y
  122. CGFloat contentY = kMargin;
  123. // CGFloat winWidth = [[UIApplication sharedApplication] statusBarFrame].size.width;
  124. // 宽度W 先假设大于一行
  125. CGFloat contentW = bgW - contentX - kMargin ;
  126. CGFloat contentH = 0;
  127. // 判断 内容够不够一行...
  128. // 根据字体得到NSString的尺寸
  129. CGSize oneLineSize = [msg.content sizeWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:kContentFnt,NSFontAttributeName, nil]];
  130. CGFloat oneLineW = oneLineSize.width;
  131. if (oneLineW < contentW) {
  132. // 如果不够一行
  133. CGFloat oneLineH = oneLineSize.height;
  134. contentX = kMargin * 2;
  135. _contentFrame = CGRectMake(contentX, contentY, oneLineW,oneLineH);
  136. contentH = oneLineH;
  137. contentW = oneLineW;
  138. // 5,重新调整 contentBgImg的frame的高度
  139. // 以下三步为OC标准代码,因为OC中不允许直接修该对象中结构体属性的成员的值,要通过中间的临时结构体变量
  140. CGRect frame = _contentBgImgFrame;
  141. frame.size.width = contentW + kMargin *3.5;
  142. frame.size.height = contentH + kMargin * 3 ;
  143. _contentBgImgFrame = frame;
  144. } else {
  145. // 如果超过一行,按下面算法计算 高度
  146. // 根据内容动态设置 高度
  147. CGRect tmpRect = [msg.content boundingRectWithSize:CGSizeMake(contentW, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:[NSDictionary dictionaryWithObjectsAndKeys:kContentFnt,NSFontAttributeName, nil] context:nil];
  148. // 高度H
  149. contentH = tmpRect.size.height;
  150. _contentFrame = CGRectMake(contentX, contentY, contentW,contentH);
  151. // 5,重新调整 contentBgImg的frame的高度
  152. // 以下三步为OC标准代码,因为OC中不允许直接修该对象中结构体属性的成员的值,要通过中间的临时结构体变量
  153. CGRect frame = _contentBgImgFrame;
  154. frame.size.height = contentH + kMargin * 3 ;
  155. _contentBgImgFrame = frame;
  156. }
  157. // 8,这个时候就可以计算最大Y 即行高了
  158. if (headImgH > _contentBgImgFrame.size.height) {
  159. _maxY = CGRectGetMaxY(_headImgFrame) + kMargin;
  160. } else {
  161. _maxY = CGRectGetMaxY(_contentBgImgFrame) + kMargin;
  162. }
  163. }
  164. @end


控制器

  1. //
  2. // BeyondViewController.m
  3. // 29_仿微信聊天
  4. //
  5. // Created by beyond on 14-9-2.
  6. // Copyright (c) 2014年 com.beyond. All rights reserved.
  7. //
  8. #import "BeyondViewController.h"
  9. #import "Msg.h"
  10. #import "BeyondCellFrame.h"
  11. #import "BeyondCell.h"
  12. @interface BeyondViewController ()
  13. {
  14. // 从plist文件中加载的所有weiboFrames(因为它已经含有一个weibo成员),返回所有的对象组成的数组
  15. NSMutableArray *_msgFrames;
  16. }
  17. @end
  18. @implementation BeyondViewController
  19. - (void)viewDidLoad
  20. {
  21. [super viewDidLoad];
  22. // 初始化 对象数组
  23. _msgFrames = [NSMutableArray array];
  24. }
  25. #pragma mark - UITextField代理,发送请求
  26. - (BOOL)textFieldShouldReturn:(UITextField *)textField
  27. {
  28. if (textField.text.length == 0){
  29. return NO;
  30. }
  31. BeyondCellFrame *frame = [[BeyondCellFrame alloc]init];
  32. // ***********设置的WeiboFrames的成员weibo的同时,进行了复杂的计算,并填充了WeiboFrames各个frame成员
  33. frame.msg = [Msg msgWithName:@"jackey" content:textField.text recordFilePath:@"NoRecord"];
  34. // 添加到对象数组
  35. [_msgFrames addObject:frame];
  36. [self.tableView reloadData];
  37. return YES;
  38. }
  39. #pragma mark - UITableView代理方法
  40. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
  41. {
  42. //去除cell间隔线
  43. tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
  44. // 返回对象数组的长度
  45. return _msgFrames.count;
  46. }
  47. // 生成自定义的cell,并传递cellFrame给它,设置好后,返回cell
  48. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  49. {
  50. // 1,从池中取
  51. BeyondCell *cell = [tableView dequeueReusableCellWithIdentifier:[BeyondCell cellID]];
  52. // 2,取不到的时候,创建一个纯洁的WeiboCell
  53. if (cell == nil) {
  54. cell = [[BeyondCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:[BeyondCell cellID]];
  55. }
  56. // 3,设置独一无二的数据
  57. BeyondCellFrame *frame = [_msgFrames objectAtIndex:indexPath.row];
  58. cell = [cell cellWithCellFrame:frame];
  59. return cell;
  60. }
  61. // cellFrame对象数组有每一行的行高,其内部已经计算好了
  62. - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
  63. {
  64. // cellFrame的成员有:Msg数据模型对象,以及根据数据模型计算出来的所有的frames,以及最大的Y即对应数据模型的行高
  65. BeyondCellFrame *frame = [_msgFrames objectAtIndex:indexPath.row];
  66. return frame.maxY;
  67. }
  68. // 恢复view全屏,并且让键盘退出
  69. - (void)exitKeyboard
  70. {
  71. [UIView animateWithDuration:0.2 animations:^{
  72. self.view.frame = CGRectMake(0, 0, self.view.frame.size.width, [[UIScreen mainScreen]bounds].size.height);
  73. }completion:^(BOOL finished){}];
  74. [_chatInput resignFirstResponder];
  75. }
  76. // 滚至表格最后一行
  77. - (void)scrollToLastCell;
  78. {
  79. if (_msgFrames.count >1) {
  80. [self.chatTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:_msgFrames.count-1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
  81. }
  82. }









声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/652286
推荐阅读
相关标签
  

闽ICP备14008679号