iOS小技能(cell的重用原理及自定义cell)

关山初度尘未洗,策马扬鞭再奋蹄!这篇文章主要讲述iOS小技能:cell的重用原理及自定义cell相关的知识,希望能为你提供帮助。
【iOS小技能(cell的重用原理及自定义cell)】

引言ios开发中,要实现表格数据展示,做常用的做法就是使用UITableView。
IUITableViewCell的简介1.1 cell的结构UITableView的每一行都是一个UITableViewCell

  1. cell的初始化: 通过datasource的tableView: cellForRowAtIndexPath: 方法来初始化每一行
  2. UITableViewCell内部有一个默认的自视图ContentView :
ContentView是UITableViewCell所显示内容的父视图,可显示一些辅助视图(辅助视图的作用是显示一个表示动作的图标);contentView 默认有3个子视图(textLabel、detailTextLabel、UIImageView)3. UITableViewCell的UITabelCellStyle属性:用于决定使用contentView的哪些子视图,以及这个视图在contentView中的位置4. cell的结构

1.2 cell的重用原理
  1. 重用原理
当滚动列表时,部分cell会移出窗口,UITableView会将窗口外的cell放入一个等待重用的对象池;当UITableView要求datasource返回cell的时候,datasource会先查看这个对象池是否有未使用的cell,若有,datasource会用新的数据配置这个cell,并返回给UITableVIew重新显示到窗口中,从而避免创建新的对象。2. 解决一个TableView同时拥有不通类型的cell的问题解决方案:在初始化cell的时候,传入一个特定的“字符串标识”(通常使用cell的类名)来给cell的reuseIdentifier属性赋值;当UITableView 要求datasource返回cell的时候,此时就利用reuseIdentifier属性到对象词中查找对应类型的cell对象,若找到就重用,否则利用这个reuseIdentifier属性来实例化一个cell对象3. cell重用的例子:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

// 1.定义一个cell的标识
static NSString *ID = @"mjcell";

// 2.从缓存池中取出cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

// 3.如果缓存池中没有cell
if (cell == nil)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];


// 4.设置cell的属性...
return cell;

  1. 单元格循环引用概念
II 使用xib封装一个View的步骤
  1. new一个xib文件来描述一个View的内部结构
  2. new一个自定义的视图类(继承自xib根对象的class),类名通常与xib文件名保存一致
  3. 将xib中的控件与自定义视图类的.m文件建立连线 (建立连线之前,对根对象的class指定为刚刚新建的控件-> 在xi b属性面板指定可重用标识符
  4. 提供一个类方法,返回一个创建好的自定义视图类(屏蔽从xib加载的过程)
5, 提供一个模型属性让外界传递模型数据,重写模型属性的setter方法(将模型数据展示到对应的子控件上面)
III delegate父控件(视图控制器)监听子控件的事件,当子控件发生某些事情的时候,通知父控件工作--备注:父控件通知子控件工作,直接调用子控件的方法即可。
如果使用强引用,将造成循环的强引用--> 儿子只能对父亲进行弱引用。
@property (nonatomic,weak) id< HSGroupBuyingFooterViewDelegate> delegate; //在oc中,只有没有强用的时候,才会被立即释放;一旦自定义视图称为视图控制器的视图包含,极自定义视图为视图控制器的儿子时,且视图控制器为自定义视图(儿子)的代理,此时如果代理是强引用,将造成循环的强引用,”你中有我,我中有你“。--永远呆在内存


3.1 delegate的使用场合
  1. 对象A内部发生了一些事情,想通知对象B,对象A想传递数据给对象B
  2. 对象B想监听对象A内部发生了什么事情
  3. 对象A想在自己的方法内部调用对象B的某些方法,并且对象A不能对对象B有耦合依赖
3.2 使用delegate的步骤
  1. 搞清楚谁 是谁的 delegate
  2. 定义代理协议(协议名称的命名规范:控件类名+Delegate)
  3. 定义代理方法:
*代理方法一般都定义为optional
*代理方法名称都以空间名开头;代理方法至少有个参数,用于将控件本事传递出去
4. 设置代理对象(代理对象遵守协议,并实现协议方法)
5. 在恰当的时刻调用delegate的协议方法,来通知delegate发生了什么事情(在调用之前判断代理是否实现了该代理方法)
IV 通过代码自定义cell
  1. new一个继承自UITableViewCell的类
  2. 重写initWithStyle: reuseIndentifier: 方法(对子控件的属性进行一次性赋值)
--有些属性只须设置一次,例如字体、固定的图片
3. 并添加需要显示的子控件到contentView中
4. 提供数据模型、frame模型
数据模型用于存放文字、图片数据;frame模型存放数据模型、所有子控件的frame、cell的高度
5. cell拥有一个frame模型
6. 重写frame模型的setter方法(设置子控件的显示数frame);对frame的对象实例化采用懒加载方法,即进行getter方法的重写
//

//HSStatusCell.h




#import < UIKit/UIKit.h>

#import "HSStatus.h"

@interface HSStatusCell : UITableViewCell

//自定义视图的现实的数据来源于模型,即使用模型装配自定义视图的显示内容

@property (nonatomic,strong) HSStatus *status; //视图对应的模型,是视图提供给外界的接口

/**

通过数据模型设置视图内容,可以让视图控制器不需要了解视图的细节

*/

+ (instancetype) tableVieCellwWithStatus:(HSStatus *) status tableView:(UITableView *)tableView; //使用类方法获取自定义视图,参数用于视图的数据装配

//

+ (instancetype) tableVieCellwWittableView:(UITableView *)tableView; //使用类方法获取自定义视图

@end

  • 设置位置
- (void)setStatus:(HSStatus *)status

_status = status;

[self settingData];

//设置位置

[self settingFrame];






- (void) settingData

//设置位置

[self.textViewsetText:self.status.text];

[self.nameView setText:self.status.name];

[self.iconView setImage:self.status.iconImage];

if (self.status.picture.length > 0)

[self.pictureView setImage:self.status.pictureImage];

[self.pictureView setHidden:NO];

else

[self.pictureView setImage:nil]; //没有配图的时候,清空图片信息--cell重用的时候,对于可选视图要进行处理

[self.pictureView setHidden:YES];






if (self.status.vip)

[self.vipView setImage:self.status.vipImage];

[self.vipView setHidden:NO]; //显示VIP视图

[self.nameView setTextColor:[UIColor redColor]];

else

[self.vipView setImage:nil]; //不是VIP的时候,清空VIP标识--cell重用的时候,针对可选视图进行特殊处理

[self.vipView setHidden:YES];

[self.nameView setTextColor:[UIColor blackColor]];








/**

设置位置信息

*/

- (void) settingFrame

//定义间距

CGFloat padding =10;

CGFloat iconX = padding;

CGFloat iconY = padding;

CGFloat iconWidth = 30;

CGFloat iconHeiht = 30;

[self.iconView setFrame:CGRectMake(iconX, iconY, iconWidth, iconHeiht)];

//设置昵称,昵称的大小由文字的长度决定

/**

1.boundingRectWithSize 方法计算给定文本所占用的区域

2.options: 计算多行的的准确高度需要传入NSStringDrawingUsesLineFragmentOrigin

3、attributes 指定字体相关属性;UIKit框架中的第一个头文件NSAttributedString.h






*/

NSDictionary *nameDict = @NSFontAttributeName:KnameFont;

CGRect nameFrame = [self.status.name boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:nameDict context:nil]; //返回一个x,y,都为0 的CGRect

nameFrame.origin.x = CGRectGetMaxX(self.iconView.frame)+padding;

nameFrame.origin.y = padding+(CGRectGetHeight(self.iconView.frame)-CGRectGetHeight(nameFrame))*0.5;



[self.nameView setFrame:nameFrame];



//设置VIP标识的frame

[self.vipView setFrame:CGRectMake(CGRectGetMaxX(self.nameView.frame)+padding, CGRectGetHeight(self.nameView.frame), 14, 14)];

//设置文本内容的frame




NSDictionary

    推荐阅读