AJ分享,必须精品

先看效果图


编程思路

代码创建Cell的步骤

1> 创建自定义Cell,继承自UITableViewCell
2> 根据需求,确定控件,并定义属性
3> 用getter方法完成控件的实例化,只创建并添加到contentView,不处理位置
4> 定义一个模型属性,通过setter方法,设置cell的显示

昵称正文字符串的位置算法

  1. 设置大小由文字的长度决定
  2. 用字符串方法:[@"" boundingRectWithSize:(CGSize) options:(NSStringDrawingOptions) attributes:(NSDictionary *) context:(NSStringDrawingContext *)]
  3. //boundingRectWithSize计算给定文字字符串所占的区域,返回是一个x,y为0的CGRect
  4. // 如果要计算多行的准确高度需要传入
  5. // options:NSStringDrawingUsesLineFragmentOrigin
  6. //attribbutes:dict 用于指定字体的相关属性的字典。UIKit框架的第一个头文件ps 这个头文件不记很难找
  7. // context :nil
  8. #define kNameFont [UIFont systemFontOfSize:14]
  9. NSDictionary *nameDict = @{NSFontAttributeName:kNameFont};
  10. CGRect nameFrame = [self.status.name boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:nameDict context:nil];

计算行高的方法

要用到代理方法的:

  1. -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

计算行高的方法,会在加载表格数据时,有多少行计算多少次 contentSize

  1. 问题:此方法执行的时候,cell还没有被实例化!
  2. 但是:行高计算是在实例化cell时,通过设置status属性,计算=》有了status模型,就可以知道行高
  3. 问题:如何在cell实例化之前,获得行高?
  4. 解决方法:通过status可以计算得到行高! = 》再建立一个模型,专门计算所有控件的位置

警告:原形单元格必须又一个可重用标示符的解决

警告:file:///Users/apple/Desktop/%E5%AD%A6%E4%B9%A0/%E4%BA%8C%E6%9C%9F%E5%AD%A6%E4%B9%A0/Day07/%E6%96%B0%E6%B5%AA%E5%BE%AE%E5%8D%9AUI/%E6%96%B0%E6%B5%AA%E5%BE%AE%E5%8D%9AUI/Base.lproj/Main.storyboard: warning: Unsupported Configuration: Prototype table cells must have reuse identifiers
警告:原形单元格必须又一个可重用标示符
解决办法是在Cell中的Identfier加入可重用标示符

然后一定要关联cell的class

——这两部可以用一行代码来代替

  1. //为tableView注册可重用单元格
  2. [self.tableView registerClass:[NYStatusCell class] forCellReuseIdentifier:ID];

这时候我们注释

  1. // if (cell == nil) {
  2. // cell = [[NYStatusCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
  3. // }

也可以运行了

  1. Storyboard中指定了可重用标示符,同时指定了Cell的类是NYStatusCell,系统会为tableView注册一个原形cell,专门用来做可重用单元格,一旦缓冲区不存在可重用单元格,系统会使用原形Cell新实例化一个Cell供程序使用!
  2. 因此如果在Storyb中,注册了原形Cell,就不需要做 cell == nil 的判断了

注意:这些在iOS6之后才有的。

代码学习

类结构

这个小项目主要由这些类组成

MVC各自负责各自的东西
Model有两个模型,一个是Status主要负责所有数据
Status中有

  1. @property (nonatomic, copy)NSString *text;
  2. @property (nonatomic, copy)NSString *icon;
  3. @property (nonatomic, copy)NSString *name;
  4. @property (nonatomic, assign)BOOL vip;
  5. @property (nonatomic, copy) NSString *picture;

这些属性主要包括头像,昵称,vip图标,正文,图片
StatusFrame模型主要负责存放每一个组件在cell所要存放的位置

  1. //提高安全性能:+readonly
  2. @property (nonatomic, assign, readonly)CGRect textF;
  3. @property (nonatomic, assign, readonly)CGRect iconF;
  4. @property (nonatomic, assign, readonly)CGRect nameF;
  5. @property (nonatomic, assign, readonly)CGRect vipF;
  6. @property (nonatomic, assign, readonly)CGRect pictureF;
  7. /**行高*/
  8. @property (nonatomic, assign)CGFloat cellHeight;
  9. /**所有控件的尺寸都可以通过Status来计算得出*/
  10. @property (nonatomic, strong)NYStatus *status;

NYViewController中的代码


  1. // NYViewController.m
  2. // 新浪微博UI
  3. //
  4. // Created by apple on 15-4-8.
  5. // Copyright (c) 2015年 znycat. All rights reserved.
  6. //
  7. #import "NYViewController.h"
  8. #import "NYStatus.h"
  9. #import "NYStatusCell.h"
  10. #import "NYStatusFrame.h"
  11. @interface NYViewController ()
  12. @property (nonatomic, strong) NSArray *statusFrames;
  13. @end
  14. @implementation NYViewController
  15. static NSString *ID = @"Cell";
  16. /**懒加载数据*/
  17. -(NSArray *)statusFrames
  18. {
  19. if (_statusFrames == nil) {
  20. _statusFrames = [NYStatusFrame statusFrames];
  21. }
  22. return _statusFrames;
  23. }
  24. -(void)viewDidLoad
  25. {
  26. [super viewDidLoad];
  27. self.tableView.contentInset = UIEdgeInsetsMake(20, 0, 0, 0);
  28. //为tableView注册可重用单元格
  29. [self.tableView registerClass:[NYStatusCell class] forCellReuseIdentifier:ID];
  30. }
  31. - (void)didReceiveMemoryWarning
  32. {
  33. [super didReceiveMemoryWarning];
  34. // Dispose of any resources that can be recreated.
  35. }
  36. #pragma mark - 数据源方法
  37. -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
  38. {
  39. return self.statusFrames.count;
  40. }
  41. -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  42. {
  43. /**
  44. 在Storyboard中指定了可重用标示符,同时指定了Cell的类是HMStatusCell
  45. 系统会为tableView注册一个原形Cell,专门用来做可重用单元格的,一旦缓冲区中不存在
  46. 可重用单元格,系统会使用原形Cell新实例化一个Cell用程序使用!
  47. 因此如果在,Storyboard中,注册了原形Cell,就不再需要 cell == nil的判断了
  48. */
  49. // NYStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
  50. // unable to dequeue a cell with identifier Cell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard
  51. // 使用这个方法,要求一定注册可重用单元格,否则就会崩溃!
  52. // 官方建议使用以下方法,利用程序的崩溃,及时发现问题
  53. NYStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:ID forIndexPath:indexPath];
  54. // if (cell == nil) {
  55. // cell = [[NYStatusCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
  56. // }
  57. NYStatusFrame *statusFrame = self.statusFrames[indexPath.row];
  58. cell.statusFrame = statusFrame;
  59. return cell;
  60. }
  61. #pragma mark - 代理方法
  62. /**计算单元格行高*/
  63. -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
  64. {
  65. /**
  66. 计算行高的方法,会在加载表格数据时,有多少行计算多少次 contentSize
  67. 问题:此方法执行的时候,cell还没有被实例化!
  68. 但是:行高计算是在实例化cell时,通过设置status属性,计算=》有了status模型,就可以知道行高 !
  69. 问题:如何在cell实例化之前,获得行高?
  70. 解决方法:通过status可以计算得到行高! = 》再建立一个模型,专门计算所有控件的位置
  71. */
  72. NYStatusFrame *statusFrame = self.statusFrames[indexPath.row];
  73. return statusFrame.cellHeight;
  74. }
  75. @end

自定义cell纯代码写NYStatusCell

  1. //
  2. // NYStatusCell.m
  3. // 新浪微博UI
  4. //
  5. // Created by apple on 15-4-9.
  6. // Copyright (c) 2015年 znycat. All rights reserved.
  7. //
  8. #import "NYStatusCell.h"
  9. #import "NYStatus.h"
  10. #import "NYStatusFrame.h"
  11. /**姓名字体*/
  12. #define kNameFont [UIFont systemFontOfSize:14]
  13. /**正文字体*/
  14. #define kTextFont [UIFont systemFontOfSize:16]
  15. @interface NYStatusCell()
  16. //1>创建自定iyiCell,继承自UITableViewCell
  17. //2>根据需求,确定控件,并定义属性。
  18. @property (nonatomic, strong) UIImageView *iconView;
  19. @property (nonatomic, strong) UILabel *nameView;
  20. @property (nonatomic, strong) UIImageView *vipView;
  21. @property (nonatomic, strong) UILabel *textView;
  22. @property (nonatomic, strong) UIImageView *pictureView;
  23. @end
  24. @implementation NYStatusCell
  25. //3>用get方法完成控件的实例化,只创建并添加到contentView,不处理位置。
  26. -(UIImageView *)iconView
  27. {
  28. if (_iconView == nil) {
  29. _iconView = [[UIImageView alloc] init];
  30. [self.contentView addSubview:_iconView];
  31. }
  32. return _iconView;
  33. }
  34. -(UILabel *)nameView
  35. {
  36. if (_nameView == nil) {
  37. _nameView = [[UILabel alloc] init];
  38. //默认字体是17号,改成kNameFont
  39. _nameView.font = kNameFont;
  40. [self.contentView addSubview:_nameView];
  41. }
  42. return _nameView;
  43. }
  44. -(UIImageView *)vipView
  45. {
  46. if (_vipView == nil) {
  47. _vipView = [[UIImageView alloc] init];
  48. [self.contentView addSubview:_vipView];
  49. }
  50. return _vipView;
  51. }
  52. -(UILabel *)textView
  53. {
  54. if (_textView == nil) {
  55. _textView = [[UILabel alloc] init];
  56. _textView.font = kTextFont;
  57. _textView.numberOfLines = 0;//让他可以换行
  58. [self.contentView addSubview:_textView];
  59. }
  60. return _textView;
  61. }
  62. -(UIImageView *)pictureView
  63. {
  64. if (_pictureView == nil) {
  65. _pictureView = [[UIImageView alloc] init];
  66. [self.contentView addSubview:_pictureView];
  67. }
  68. return _pictureView;
  69. }
  70. -(void)setStatusFrame:(NYStatusFrame *)statusFrame
  71. {
  72. _statusFrame = statusFrame;
  73. //1>设置数据
  74. [self settingData];
  75. //2>设置位置
  76. [self settingFrame];
  77. }
  78. /**设置数据*/
  79. -(void)settingData
  80. {
  81. NYStatus *status = self.statusFrame.status;
  82. //头像
  83. self.iconView.image = [UIImage imageNamed:status.icon];
  84. //姓名
  85. self.nameView.text = status.name;
  86. //vip
  87. if (status.vip) {
  88. self.vipView.image = [UIImage imageNamed:@"vip"];
  89. }
  90. //内容正文
  91. self.textView.text = status.text;
  92. //图片可选参数:
  93. if (status.picture.length > 0) {
  94. self.pictureView.hidden = YES;
  95. self.pictureView.image = [UIImage imageNamed:status.picture];
  96. }
  97. self.pictureView.hidden = NO;
  98. }
  99. /**设置位置*/
  100. -(void)settingFrame
  101. {
  102. //1.头像
  103. self.iconView.frame = self.statusFrame.iconF;
  104. //2,姓名大小由文字的长度决定
  105. //boundingRectWithSize计算给定文字字符串所占的区域,返回是一个x,y为0的CGRect;w,h是计算好的宽高
  106. // 如果要计算多行的准确高度需要传入
  107. // options:NSStringDrawingUsesLineFragmentOrigin
  108. //attribbutes:dict 用于指定字体的相关属性的字典。UIKit框架的第一个头文件ps 这个头文件不记很难找
  109. // context :nil
  110. self.nameView.frame = self.statusFrame.nameF;
  111. //3,vip图片
  112. self.vipView.frame = self.statusFrame.vipF;
  113. //4,正文
  114. self.textView.frame = self.statusFrame.textF;
  115. //5,图片
  116. self.pictureView.frame = self.statusFrame.pictureF;
  117. }
  118. @end

模型实现方法

NYStatus

  1. //
  2. // NYStatus.m
  3. // 新浪微博UI
  4. //
  5. // Created by apple on 15-4-8.
  6. // Copyright (c) 2015年 znycat. All rights reserved.
  7. //
  8. #import "NYStatus.h"
  9. @implementation NYStatus
  10. -(instancetype)initWithDict:(NSDictionary *)dict
  11. {
  12. self = [super init];
  13. if (self) {
  14. [self setValuesForKeysWithDictionary:dict];
  15. }
  16. return self;
  17. }
  18. +(instancetype)statusWithDict:(NSDictionary *)dict
  19. {
  20. return [[self alloc] initWithDict:dict];
  21. }
  22. +(NSArray *)statuses
  23. {
  24. NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"statuses.plist" ofType:nil]];
  25. NSMutableArray *arrayM = [NSMutableArray array];
  26. for (NSDictionary *dict in array) {
  27. [arrayM addObject:[self statusWithDict:dict]];
  28. }
  29. return arrayM;
  30. }
  31. @end

NYStatusFrame

  1. //
  2. // NYStatusFrame.m
  3. // 新浪微博UI
  4. //
  5. // Created by apple on 15-4-9.
  6. // Copyright (c) 2015年 znycat. All rights reserved.
  7. //
  8. #import "NYStatusFrame.h"
  9. #import "NYStatus.h"
  10. #import "NSString+Tools.h"
  11. #define kNameFont [UIFont systemFontOfSize:14]
  12. /**正文字体*/
  13. #define kTextFont [UIFont systemFontOfSize:16]
  14. @implementation NYStatusFrame
  15. /**
  16. 为了程序的安全(面向对象的思想,你给我你就相信我,让我来改,别人别随便动)
  17. 为了让程序更安全,我们将类NYStatusFrame的有关位置的:(例如iconF)设置成readonly只读属性,这时候我们用self.iconF(_iconF的set方法)的时候就不能用了。
  18. 此时要注意:
  19. 一旦重写了readonly属性的getter方法,
  20. -(CGRect)iconF
  21. {
  22. }
  23. 带_的成员变量就不存在了
  24. 这时候如果还需要使用_成员变量,则必须用合成指令@synthesize
  25. @synthesize iconF = _iconF;
  26. */
  27. -(void)setStatus:(NYStatus *)status
  28. {
  29. _status = status;
  30. //0.定义间距
  31. CGFloat padding = 10;
  32. //1.头像
  33. CGFloat iconX = padding;
  34. CGFloat iconY = padding;
  35. CGFloat iconW = 30;
  36. CGFloat iconH = 30;
  37. _iconF = CGRectMake(iconX, iconY, iconW, iconH);
  38. //2,姓名大小由文字的长度决定
  39. //boundingRectWithSize计算给定文字字符串所占的区域,返回是一个x,y为0的CGRect;w,h是计算好的宽高
  40. // 如果要计算多行的准确高度需要传入
  41. // options:NSStringDrawingUsesLineFragmentOrigin
  42. //attribbutes:dict 用于指定字体的相关属性的字典。UIKit框架的第一个头文件ps 这个头文件不记很难找
  43. // context :nil
  44. NSDictionary *nameDict = @{NSFontAttributeName:kNameFont};
  45. // CGRect nameFrame = [self.status.name boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:nameDict context:nil];
  46. CGRect nameFrame = [self.status.name textRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) attributes:nameDict];
  47. nameFrame.origin.x = CGRectGetMaxX(self.iconF) +padding;
  48. nameFrame.origin.y = padding + (self.iconF.size.height - nameFrame.size.height)*0.5;
  49. _nameF = nameFrame;
  50. //3,vip图片
  51. CGFloat vipX = CGRectGetMaxX(self.nameF) + padding;
  52. CGFloat vipY = self.nameF.origin.y;
  53. CGFloat vipW = 14;
  54. CGFloat vipH = 14;
  55. _vipF = CGRectMake(vipX, vipY, vipW, vipH);
  56. //4,正文
  57. NSDictionary *textDict = @{NSFontAttributeName:kTextFont};
  58. // CGRect textFrame = [self.status.text boundingRectWithSize:CGSizeMake(300, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:textDict context:nil];
  59. CGRect textFrame = [self.status.text textRectWithSize:CGSizeMake(300, MAXFLOAT) attributes:textDict];
  60. textFrame.origin.x = padding;
  61. textFrame.origin.y = CGRectGetMaxY(self.iconF) + padding;
  62. _textF = textFrame;
  63. //5,配图
  64. if (self.status.picture.length>0) {
  65. CGFloat pictureX = padding;
  66. CGFloat pictureY = CGRectGetMaxY(self.iconF) + padding +self.textF.size.height +padding;
  67. CGFloat pictureW = 100;
  68. CGFloat pictureH = 100;
  69. _pictureF= CGRectMake(pictureX, pictureY, pictureW, pictureH);
  70. self.cellHeight = CGRectGetMaxY(self.pictureF) + padding;
  71. }else{
  72. self.cellHeight = CGRectGetMaxY(self.textF) + padding;
  73. }
  74. }
  75. +(NSArray *)statusFrames
  76. {
  77. NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"statuses.plist" ofType:nil]];
  78. NSMutableArray *arrayM = [NSMutableArray array];
  79. for (NSDictionary *dict in array) {
  80. //要添加statusesFrame对象
  81. NYStatusFrame *statusFrame = [[NYStatusFrame alloc]init];
  82. //调用statusFrame的setter方法,保存status模型,同时计算出控件的位置(setter方法中进行的)
  83. statusFrame.status = [NYStatus statusWithDict:dict];
  84. //将statusFrame添加到数组
  85. [arrayM addObject:statusFrame];
  86. }
  87. return arrayM;
  88. }
  89. @end

AJ学IOS(17)UI之纯代码自定义Cell实现新浪微博UI的更多相关文章

  1. iOS开发小技巧--纯代码自定义cell

    纯代码自定义cell 自定义cell的步骤(每个cell的高度不一样,每个cell里面显示的内容也不一样) 1.新建一个继承自UITableViewCell的子类 2.在initWithStyle:方 ...

  2. AJ学IOS 之微博项目实战(10)微博cell中图片的显示以及各种填充模式简介

    AJ分享,必须精品 :一效果 如果直接设置会有拉伸等等的状况,这里主要介绍图片显示的一些细节 二:代码 代码实现其实很简单,微博当中用了一个photos来存放九宫格这些图片,然后用了一个photo类来 ...

  3. ios开发UI篇—使用纯代码自定义UItableviewcell实现一个简单的微博界面布局

    本文转自 :http://www.cnblogs.com/wendingding/p/3761730.html ios开发UI篇—使用纯代码自定义UItableviewcell实现一个简单的微博界面布 ...

  4. AJ学IOS(16)UI之XIB自定义Cell实现团购UI

    AJ分享,必须精品 先看效果图 自定义Cell 本次主要是自定义Cell的学习 实现自定义Cell主要有三种方法:按照使用的频繁度排序: XIB > 纯代码 > StoryBoard XI ...

  5. 李洪强iOS开发之后使用纯代码实现横向滚动的UIScrollView

    李洪强iOS开发之后使用纯代码实现横向滚动的UIScrollView (VTmagic是一个实现左右滚动的控制器的框架,也可以实现此功能) 实现的效果:  01 - 创建四个控制器 02 - 定义需要 ...

  6. iOS回顾笔记(08) -- 自定义Cell的类型和创建步骤总结

    iOS回顾笔记(08) -- 自定义Cell的类型和创建步骤总结 项目中我们常见的自定义cell主要分为两种 等高cell:如应用列表.功能列表 非等高cell:如微博列表.QQ聊天页面 下面对这 ...

  7. 通过代码自定义cell 新浪微博页面显示

    通过代码自定义cell(cell的高度不一致)(如果高度一致的cell 用xib实现) 1.新建一个集成自UItableVIewCell的类 2.重写initWithStle :方法 - (insta ...

  8. AJ学IOS(03)UI之纯代码实现UI——图片查看器

    AJ分享,必须精品 先看效果 主要实现类似看新闻的一个界面,不用拖拽,纯代码手工写. 首先分析app可以很容易知道他这里有两个UILabel一个UIImageView还有两个UIButton 定义UI ...

  9. AJ学IOS(41)UI之核心动画 两行代码搞定3D转场

    AJ分享,必须精品 效果: 代码: 其实代码很少,苹果都给封装好了 // 1.创建核心动画 CATransition *ca = [CATransition animation]; // 1.1动画过 ...

随机推荐

  1. Java 借助poi操作PDF工具类

    ​ 一直以来说写一个关于Java操作PDF的工具类,也没有时间去写,今天抽空写一个简单的工具类,拥有PDF中 换行,字体大小,字体设置,字体颜色,首行缩进,居中,居左,居右,增加新一页等功能,如果需要 ...

  2. KMP 算法简单解释

    ​ 讲KMP算法,离不开BF,实际上,KMP就是BF升级版,主要流程和BF一样 ​ 不同是在匹配失败时能利用子串的特征减少回溯,利用根据子串特征生成的Next数组来减少 <( ̄︶ ̄)↗[GO!] ...

  3. 【转载】因为我们是OIer

    我们是OIer, 所以我们 不用在跑道上挥汗如雨: 不用在球场上健步如飞: 更不用在没事的时候, 经受非人的体能训练-- 但是, 我们却要把头脑 高速运转, 还要接受一大堆 大学生也只是 " ...

  4. intern()方法的使用

    intern() intern方法的作用是:如果字符串常量池中已经包含一个字符串等于此String对象的字符串,则返回常量池中的这个String对应的对象, 否则将其添加到常量池并返回常量池中的引用. ...

  5. VScode+phpStudy搭建php代码调试环境

    一.安装Visual Studio Code 官网:https://code.visualstudio.com/ 下载安装包后,按照默认安装即可 安装中文语言环境 点击左侧工具栏的 extension ...

  6. 在django中如何从零开始搭建一个mock服务

    mock概念 mock 就是模拟接口返回的一系列数据,用自定义的数据替换接口实际需要返回的数据,通过自定义的数据来实现对下级接口模块的测试.这里分为两类测试:一类是前端对接口的mock,一类是后端单元 ...

  7. 从阿里、腾讯的面试真题中总结了这11个Redis高频面试题

    前言 现在大家的工作生活基本已经是回归正轨了,最近也是迎来了跳槽面试季,有些人已经拿到了一两个offer了. 这段时间收集了阿里.腾讯.百度.京东.美团.字节跳动等公司的Java面试题,总结了Redi ...

  8. Swagger2 初始用

    1.结合Spring-Boot 引入 pom 依赖  <dependency> <groupId>io.springfox</groupId> <artifa ...

  9. 如何测试Linux命令运行时间?

    良许在工作中,写过一个 Shell 脚本,这个脚本可以从 4 个 NTP 服务器轮流获取时间,然后将最可靠的时间设置为系统时间. 因为我们对于时间的要求比较高,需要在短时间内就获取到正确的时间.所以我 ...

  10. Django之环境安装

    什么是Django Python下有许多款不同的 Web 框架.Django是重量级选手中最有代表性的一位.许多成功的网站和APP都基于Django. Django是一个开放源代码的Web应用框架,由 ...