300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > 自定义UITableViewCell新浪微博

自定义UITableViewCell新浪微博

时间:2020-09-24 15:57:53

相关推荐

自定义UITableViewCell新浪微博

自定义UITableViewCell新浪微博

自定义 UITableViewCell的步骤:

1. 新建一个继承自 UITableViewCell 的类

2. 重写 initWithStyle:reuseIdentifier: 方法

添加所有需要显示的子控件 ( 不需要设置子控件的数据和 frame, 子控件要添加到 contentView 中 )

进行子控件一次性的属性设置 ( 有些属性只需要设置一次 , 比如字体 \ 固定的图片 )

3. 提供 2 个模型

数据模型 : 存放文字数据 \ 图片数据

frame 模型 : 存放数据模型 \ 所有子控件的 frame\cell 的高度

4. cell 拥有一个 frame 模型 ( 不要直接拥有数据模型 )

5. 重写 frame 模型属性的 setter 方法 : 在这个方法中设置子控件的显示数据和 frame

6.f rame 模型数据的初始化已经采取懒加载的方式 ( 每一个 cell 对应的 frame 模型数据只加载一次 )

步骤一:根据 plist文件,创建Model层数据。

@property ( nonatomic , copy ) NSString *text; // 正文

@property ( nonatomic , copy ) NSString *icon; // 头像

@property ( nonatomic , copy ) NSString *picture; // 图片

@property ( nonatomic , copy ) NSString *name; // name

@property ( nonatomic , assign ) BOOL vip; // vip

+ ( instancetype )weiboWithDict:( NSDictionary *)dict;

- ( instancetype )initWithDict:( NSDictionary *)dict;

+ ( NSArray *) weibos ;

- ( instancetype )initWithDict:( NSDictionary *)dict

{

if ( self = [ super init ]) {

[ self setValuesForKeysWithDictionary :dict];

}

return self ;

}

+ ( instancetype )weiboWithDict:( NSDictionary *)dict

{

return [[ self alloc ] initWithDict :dict];

}

+ ( NSArray *)weibos

{

NSArray *array = [ NSArray arrayWithContentsOfFile :[[ NSBundle mainBundle ] pathForResource : @"statuses.plist" ofType : nil ]];

NSMutableArray *arrayM = [ NSMutableArray array ];

for ( NSDictionary *dict in array) {

[arrayM addObject :[ self statusWithDict :dict]];

}

return arrayM;

}

步骤二:实现数据源方法,查看数据是否能显示出来。 - ( NSArray *)weibos

{

if ( _weibos == nil ) {

_weibos = [ SUNWeiboItem weibos ]; }

return _weibos ;

}

#pragma mark - 数据源方法

- ( NSInteger )tableView:( UITableView *)tableView numberOfRowsInSection:( NSInteger )section

{

return self . statuses . count ;

}

- ( UITableViewCell *)tableView:( UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath *)indexPath

{

static NSString *ID = @"cell" ;

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier :ID];

if (cell == nil ) {

cell = [[ UITableViewCell alloc ] initWithStyle : UITableViewCellStyleDefault reuseIdentifier :ID];

}

SUNWeiboItem *weiboItem = self . statuses [indexPath. row ];

cell. textLabel . text = weiboItem. name ;

return cell;

}

步骤三:创建自定义 SUNWeiboCell , 继承自 UITableViewCell, 根据需求,确定控件,并定义属性。 @property ( nonatomic , strong ) UIImageView *iconView;

@property ( nonatomic , strong ) UILabel *nameView;

@property ( nonatomic , strong ) UIImageView *vipView;

@property ( nonatomic , strong ) UILabel *textView;

@property ( nonatomic , strong ) UIImageView *pictureView;

步骤四、 用 getter 方法完成控件的实例化,只创建并添加到 contentView ,不处理位置。 /** 姓名字体 */

#define kNameFont [UIFont systemFontOfSize: 14 ]

/** 正文字体 */

#define kTextFont [UIFont systemFontOfSize: 16 ]

- ( UIImageView *)iconView

{

if ( _iconView == nil ) {

_iconView = [[ UIImageView alloc ] init ];

[ self . contentView addSubview : _iconView ];

}

return _iconView ;

}

- ( UILabel *)nameView

{

if ( _nameView == nil ) {

_nameView = [[ UILabel alloc ] init ];

// 默认字体是 17 号

_nameView . font = kNameFont ;

[ self . contentView addSubview : _nameView ];

}

return _nameView ;

}

注意: UILabel中默认的字体是17号。

- ( UIImageView *)vipView

{

if ( _vipView == nil ) {

_vipView = [[ UIImageView alloc ] init ];

_vipView . image = [ UIImage imageNamed : @"vip" ];

_vipView . hidden = YES ;

[ self . contentView addSubview : _vipView ];

}

return _vipView ;

}

- ( UILabel *)textView

{

if ( _textView == nil ) {

_textView = [[ UILabel alloc ] init ];

_textView . font = kTextFont ;

_textView . numberOfLines = 0 ;

[ self . contentView addSubview : _textView ];

}

return _textView ;

}

注意: numberOfLines属性是换行的意思。

- ( UIImageView *)pictureView

{

if ( _pictureView == nil ) {

_pictureView = [[ UIImageView alloc ] init ];

[ self . contentView addSubview : _pictureView ];

}

return _pictureView ;

}

步骤五:在自定义cell里面, 定义一个模型属性,通过 setter 方法,设置 cell 的显示。 @property ( nonatomic , strong ) SUNWeiboItem *weiboItem;

- ( void )setWeiboItem:( SUNWeiboItem *)weiboItem

{

_weiboItem = weiboItem;

// 1> 设置数据

[ self settingData ];

// 2> 设置位置

[ self settingFrame ];

}

注意: 在主方法中,代码不宜过长。 /** 设置数据 */

- ( void )settingData

{

// 头像

self . iconView . image = [ UIImage imageNamed : self . weiboItem . icon ];

// 姓名

self . nameView . text = self . weiboItem . name ;

// vip( 可选的 )

if ( self . weiboItem . vip ) {

self . vipView . hidden = NO ;

self . nameView . textColor = [ UIColor redColor ];

} else {

self . vipView . hidden = YES ;

self . nameView . textColor = [ UIColor blackColor ];

}

// 正文

self . textView . text = self . weiboItem . text ;

// 配图 ( 可选参数 )

if ( self . weiboItem . picture . length > 0 ) {

self . pictureView . hidden = NO ;

self . pictureView . image = [ UIImage imageNamed : self . weiboItem . picture ];

} else {

self . pictureView . hidden = YES ;

}

}

/** 设置位置 */

- ( void )settingFrame

{

// 0. 定义间距

CGFloat padding = 10 ;

// 1. 头像

CGFloat iconX = padding;

CGFloat iconY = padding;

CGFloat iconW = 30 ;

CGFloat iconH = 30 ;

self . iconView . frame = CGRectMake (iconX, iconY, iconW, iconH);

// 2. 姓名大小由文字的长度来决定

NSDictionary *nameDict = @{NSFontAttributeName : kNameFont } ;

CGRect nameFrame = [ weiboItem . name boundingRectWithSize : CGSizeMake ( MAXFLOAT , MAXFLOAT ) options : NSStringDrawingUsesLineFragmentOrigin attributes :nameDict context : nil ];

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

nameFrame. origin . y = padding + ( self . iconView . bounds . size . height - nameFrame. size . height ) * 0.5 ;

self . nameView . frame = nameFrame;

注意:文字的大小,最好和vip图标的宽度一致,这样比较容易计算出vip的位置。

// vip 图标

CGFloat vipX = CGRectGetMaxX ( self . nameView . frame ) + padding;

CGFloat vipY = self . nameView . frame . origin . y ;

CGFloat vipW = 14 ;

CGFloat vipH = 14 ;

self . vipView . frame = CGRectMake (vipX, vipY, vipW, vipH);

// 正文

NSDictionary *textDict = @{NSFontAttributeName : kTextFont } ;

CGRect textFrame = [ weiboItem . text boundingRectWithSize : CGSizeMake ( 300 , MAXFLOAT ) options : NSStringDrawingUsesLineFragmentOrigin attributes :textDict context : nil ];

textFrame. origin . x = padding;

textFrame. origin . y = CGRectGetMaxY ( self . iconView . frame ) + padding;

self . textView . frame = textFrame;

注意: boundingRectWithSize属性,如果文字不换行的话,可以设置为CGSizeMake(MAXFLOAT,MAXFLOAT)。如果文字需要换行的话,需要指定宽度,即CGSizeMake(300,MAXFLOAT)。

CGFloat cellHeight;

if ( weiboItem . picture . length > 0 ) {

// 配图

CGFloat pictureX = padding;

CGFloat pictureY = CGRectGetMaxY (textFrame) + padding;

CGFloat pictureW = 100 ;

CGFloat pictureH = 100 ;

self . pictureView . frame = CGRectMake (pictureX, pictureY, pictureW, pictureH);

注意: 一般在自定义表格中的配图的宽度和高度是固定死的,这样容易计算配图的位置。 cellHeight = CGRectGetMaxY ( self . pictureView . frame ) + padding;

} else {

cellHeight = CGRectGetMaxY ( self . textView . frame ) + padding;

}

}

注意: 1.boundingRectWithSize计算给定文本字符串所占的区域,返回值是一个x,y = 0的CGRect,w,h是计算好的宽高。 2.如果要计算多行的准确高度,需要传入NSStringDrawingUsesLineFragmentOrigin选项。

3.attributes属性用于指定字体的相关属性的字典,UIKit框架中的第一个头文件。 4.context: nil

步骤六、在控制器实现 UITableView的代理方法调整为 #pragma mark - 数据源方法

- ( NSInteger )tableView:( UITableView *)tableView numberOfRowsInSection:( NSInteger )section

{

return self . statuses . count ;

}

- ( UITableViewCell *)tableView:( UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath *)indexPath

{NSLog ( @“222222222222222222" );

static NSString *ID = @"cell" ;

SUNWeiboCell *cell = [tableView dequeueReusableCellWithIdentifier :ID];

if (cell == nil ) {

cell = [[ SUNWeiboCell alloc ] initWithStyle : UITableViewCellStyleDefault reuseIdentifier :ID];

}

cell. weiboItem = self . statuses [indexPath. row ];

return cell;

}

/** 计算单元格行高 */

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

{

NSLog ( @"111111111111111111111" );

return 200 ;

}

问题分析:

1.在加载表格数据调用此方法前- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath,会首先调用- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath方法计算所有单元格的高度,而此时单元格尚未被实例化。 2.因此获取每一行的高度,不能直接从cell对象中获取,因为那时候还没创建cell对象,因此我们需要另外创建一个模型,用来管理cell内部所有子控件的frame和cell的总高度。

解决思路:既然"单元格的行高是通过模型的实际内容”计算的。

那么,在加载数据模型时,应该就可以准确地计算出每一行的准确行高了。

解决办法:创建 SUNWeiboFrameItem 模型,专门处理行高的计算。

步骤七、 创建 SUNWeiboFrameItem 模型,专门处理行高的计算。 /** 专门计算所有控件位置 */

@interface SUNWeiboFrameItem : NSObject

@property ( nonatomic , assign ) CGRect iconImageViewF; // 头像 View

@property ( nonatomic , assign ) CGRect titleLabelF; // nameView

@property ( nonatomic , assign ) CGRect pictureImageF; // 图片 View

@property ( nonatomic , assign ) CGRect zwLabelF; // 正文 Label

@property ( nonatomic , assign ) CGRect vipImageViewF; // vip

/** 行高 */

@property ( nonatomic , assign ) CGFloat cellHeight;

/** 所有控件的尺寸都可以通过 Status 来计算得出 */

@property ( nonatomic , strong ) SUNWeiboItem *weiboItem;

+ ( NSArray *)weiboFrames;

@end

注意:创建 SUNWeiboFrameItem模型,通过setter方法计算行高。 - ( void )setWeiboItem:( SUNWeiboItem *)weiboItem

{

_weiboItem = weiboItem;

// 0. 定义间距

CGFloat padding = 10 ;

// 1. 头像

CGFloat iconX = padding;

CGFloat iconY = padding;

CGFloat iconW = 30 ;

CGFloat iconH = 30 ;

self . iconImageViewF = CGRectMake (iconX, iconY, iconW, iconH);

// 2. 姓名大小由文字的长度来决定

NSDictionary *nameDict = @{NSFontAttributeName : kNameFont } ;

CGRect nameFrame = [ self . weiboItem . name boundingRectWithSize : CGSizeMake ( MAXFLOAT , MAXFLOAT ) options : NSStringDrawingUsesLineFragmentOrigin attributes :nameDict context : nil ];

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

nameFrame. origin . y = padding + ( self . iconImageViewF . size . height - nameFrame. size . height ) * 0.5 ;

self . titleLabelF = nameFrame;

// vip 图标

CGFloat vipX = CGRectGetMaxX ( self . titleLabelF ) + padding;

CGFloat vipY = self . titleLabelF . origin . y ;

CGFloat vipW = 14 ;

CGFloat vipH = 14 ;

self . vipImageViewF = CGRectMake (vipX, vipY, vipW, vipH);

// 正文

NSDictionary *textDict = @{NSFontAttributeName : kTextFont } ;

CGRect textFrame = [ self . weiboItem . text boundingRectWithSize : CGSizeMake ( 300 , MAXFLOAT ) options : NSStringDrawingUsesLineFragmentOrigin attributes :textDict context : nil ];

textFrame. origin . x = padding;

textFrame. origin . y = CGRectGetMaxY ( self . iconImageViewF ) + padding;

self . zwLabelF = textFrame;

if ( self . weiboItem . picture . length > 0 ) {

// 配图

CGFloat pictureX = padding;

CGFloat pictureY = CGRectGetMaxY (textFrame) + padding;

CGFloat pictureW = 100 ;

CGFloat pictureH = 100 ;

self . pictureImageF = CGRectMake (pictureX, pictureY, pictureW, pictureH);

self . cellHeight = CGRectGetMaxY ( self . pictureImageF ) + padding;

} else {

self . cellHeight = CGRectGetMaxY ( self . zwLabelF ) + padding;

}

}

+ ( NSArray *)weiboFrames

{

NSString *filePath = [[ NSBundle mainBundle ] pathForResource : @"statuses.plist" ofType : nil ];

NSArray *array = [ NSArray arrayWithContentsOfFile :filePath];

NSMutableArray *arrayM = [ NSMutableArray array ];

for ( NSDictionary *dict in array) {

SUNWeiboFrameItem *weiboFrameItem = [[ SUNWeiboFrameItem alloc ] init ];

weiboFrameItem. weiboItem = [ SUNWeiboItem weiboWithDict :dict];

[arrayM addObject :weiboFrameItem];

}

return arrayM;

}

注意: 所有的单元格控件的计算都是重复的,而且每次表格滚动,设置内容都会重新计算。

解决这个问题:

SUNWeiboFrameItem模型中,已经包含了 weiboItem属性。

目前控制器中的数组保存的是 weiboItem模型,将 weiboItem模型替换为SUNWeiboFrameItem模型{weiboItem,所有控件的位置},同样具有weiboItem模型。

步骤八、重构调整 SUNWeiboItem 和 SUNWeiboFrameItem 在 SUNWeiboItem模型中删除 weibos数组。 在 SUNWeiboFrameItem添加 weiboFrames数组。

步骤九、重构控制器 实现 UITableView的代理方法调整为

- ( NSArray *)weiboFrames

{

if ( _weiboFrames == nil ) {

_weiboFrames = [ SUNWeiboFrameItem weiboFrames ];

}

return _weiboFrames ;

}

注意: weiboFrames数组要改变成SUNWeiboFrameItem的模型数据。

#pragma mark - 数据源方法

- ( NSInteger )tableView:( UITableView *)tableView numberOfRowsInSection:( NSInteger )section

{

return self . weiboFrames . count ;

}

- ( UITableViewCell *)tableView:( UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath *)indexPath

{

static NSString *ID = @"cell" ;

SUNWeiboCell *cell = [tableView dequeueReusableCellWithIdentifier :ID];

if (cell == nil ) {

cell = [[ SUNWeiboCell alloc ] initWithStyle : UITableViewCellStyleDefault reuseIdentifier :ID];

}

SUNWeiboFrameItem *weiboFrameItem = self . weiboFrames [indexPath. row ];

cell. weiboItem = weiboFrameItem. weiboItem ;

return cell;

}

/** 计算单元格行高 */

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

{

NSLog ( @"111111111111111111111" );

SUNWeiboFrameItem *weiboFrameItem = self . weiboFrames [indexPath. row ];

return weiboFrameItem. cellHeight ;

}

问题分析: cell中的控件的位置计算,依然是自己计算的。

解决办法:将cell中的status替换为statusFrame就可以拿到控件位置。

步骤十、重构 自定义 SUNWeiboCell,将 SUNWeiboItem模型数据替换为 SUNWeiboFrameItem模型数据。 @property ( nonatomic , strong ) SUNWeiboItem *weiboItem;

- ( void )setWeiboFrameItem:( SUNWeiboFrameItem *)weiboFrameItem

{

_weiboFrameItem = weiboFrameItem;

// 1> 设置数据

[ self settingData ];

// 2> 设置位置

[ self settingFrame ];

}

/** 设置数据 */

- ( void )settingData

{

SUNWeiboItem *weiboItem = self . weiboFrameItem . weiboItem ;

// 头像

self . iconView . image = [ UIImage imageNamed :weiboItem. icon ];

// 姓名

self . nameView . text = weiboItem. name ;

// vip( 可选的 )

if (weiboItem. vip ) {

self . vipView . hidden = NO ;

self . nameView . textColor = [ UIColor redColor ];

} else {

self . vipView . hidden = YES ;

self . nameView . textColor = [ UIColor blackColor ];

}

// 正文

self . textView . text = weiboItem. text ;

// 配图 ( 可选参数 )

// imageNamed:nil CUICatalog: Invalid asset name supplied: (null), or invalid scale factor: 2.000000

if (weiboItem. picture . length > 0 ) {

self . pictureView . hidden = NO ;

self . pictureView . image = [ UIImage imageNamed :weiboItem. picture ];

} else {

self . pictureView . hidden = YES ;

}

}

/** 设置位置 */

- ( void )settingFrame

{

self . iconView . frame = self . weiboFrameItem . iconImageViewF ;

// 2. 姓名大小由文字的长度来决定

self . nameView . frame = self . weiboFrameItem . titleLabelF ;

// vip 图标

self . vipView . frame = self . weiboFrameItem . vipImageViewF ;

// 正文

self . textView . frame = self . weiboFrameItem . zwLabelF ;

if ( self . weiboFrameItem . weiboItem . picture . length > 0 ) {

// 配图

self . pictureView . frame = self . weiboFrameItem . pictureImageF ;

}

}

步骤十一、 重构控制器 实现 UITableView的代理方法调整为 - ( UITableViewCell *)tableView:( UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath *)indexPath

{

static NSString *ID = @"cell" ;

SUNWeiboCell *cell = [tableView dequeueReusableCellWithIdentifier :ID];

if (cell == nil ) {

cell = [[ SUNWeiboCell alloc ] initWithStyle : UITableViewCellStyleDefault reuseIdentifier :ID];

}

cell. weiboFrameItem = self . weiboFrames [indexPath. row ];

return cell;

}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。