「这是我参与2022首次更文挑战的第36天,活动详情查看:2022首次更文挑战」。
引言
iOS开发中,要实现表格数据展示,做常用的做法就是使用UITableView。
I cell类型&右侧视图及代理方法
1.1 设置右侧视图
- UITableViewCellAccessoryDisclosureIndicator 箭头,可以提示用户们当前行是可以点击的,通常选择行会跳到新的页面
- UITableViewCellAccessoryDetailButton 按钮,通常点击按钮可以做独立的操作,例如进行alertView;点击按钮并不会选中行
- UITableViewCellAccessoryDetailDisclosureButton 箭头+按钮,它们是各自工作的控件
- UITableViewCellAccessoryCheckmark 对号,通常提示用户该行数据设置完毕,使用的比较少
/**
*/
[cell setAccessoryType:UITableViewCellAccessoryDetailDisclosureButton];
1.2 自定义右侧控件
setAccessoryType 不满足实现的时候,才使用setAccessoryView进行自定义控件
setAccessoryView需要自行添加监听方法,应用场景通常是自定义cell,监听方法不要写在视图控制器中。
/**
*/
UISwitch *switcher = [[UISwitch alloc] init];
[switcher addTarget:self action:@selector(updateSwitcher) forControlEvents:UIControlEventValueChanged];
[cell setAccessoryView: switcher];
1.3 相关代理方法
#pragma mark - 代理方法通常没有返回值
/**
点击右侧按钮的监听方法,此协议方法只为setAccessoryType服务,对于自定义控件setAccessoryView不会进行响应
*/
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath{
NSLog(@"%d,%s",indexPath.row,__func__);
}
//取消选择某一行,有箭头的,极少使用此协议方法,极容易出错
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{
// NSLog(@"%d,%s",indexPath.row,__func__);
}
//选中某一行,有箭头的
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
// NSLog(@"%d,%s",indexPath.row,__func__);
}
II 例子:新浪微博
获取demo源码,请关注#公众号:iOS逆向。
2.1 cellHeight 可以通过Status计算
- 利用数据模型计算控件位置及计算cell的行高
/** 利用数据模型计算控件位置-》计算cell的行高/
- (void)setCellHeight{
CGFloat picHeight = (self.status.picture.length >0) ? KPading+CGRectGetHeight(self.pictureViewFrame): 0;
_cellHeight = CGRectGetHeight(self.iconViewFrame)+CGRectGetHeight(self.textViewFrame)+picHeight+2*KPading;
}
2.2 Frame模型替代数据模型
- 数据模型用于存放文字、图片数据。
- frame模型存放数据模型、所有子控件的frame、cell的高度。
-
目前存在什么问题? 所有的单元格控件的计算都是重复的,而且每次表格滚动,设置内容都会重新计算。
-
解决这个问题: 目前控制器中的数组保存的是status模型,将status模型替换为statusFrame模型{status,所有控件的位置},同样具有status模型
-
解决步骤:
只是修改视图控制器中的代码,暂时不要动cell。 --(将原有的status模型替换为statusFrame模型)
重写statusFrame set方法--设置子控件的显示数frame
重构代码一定要小步来
//
#import "HSStatusFrame.h"
#define KPading 10
#define KnameFont [UIFont systemFontOfSize:14]
#define KtextFont [UIFont systemFontOfSize:16]
@interface HSStatusFrame ()
//重写frame模型的setter方法(设置子控件的显示数frame);对frame的对象实例化采用懒加载方法,即进行getter方法的重写
@end
@implementation HSStatusFrame
-(void)setStatus:(HSStatus *)status{
_status = status;
[self setIconViewFrame];
[self setNameViewFrame];
[self setVipViewFrame];
[self setTextViewFrame];
[self setPictureViewFrame];
[self setCellHeight];
}
/** 计算头像控件的frame*/
- (CGRect)setIconViewFrame{
//定义间距
CGFloat iconX = KPading;
CGFloat iconY = KPading;
CGFloat iconWidth = 30;
CGFloat iconHeiht = 30;
_iconViewFrame= CGRectMake(iconX, iconY, iconWidth, iconHeiht);
return _iconViewFrame;
}
- (void)setNameViewFrame {
//设置昵称,昵称的大小由文字的长度决定
/**
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.iconViewFrame)+KPading;
nameFrame.origin.y = KPading+(CGRectGetHeight(self.iconViewFrame)-CGRectGetHeight(nameFrame))*0.5;
_nameViewFrame =nameFrame;
}
- (void)setVipViewFrame{
_VipViewFrame = CGRectMake(CGRectGetMaxX(self.nameViewFrame)+KPading, CGRectGetHeight(self.nameViewFrame), 14, 14);
}
- (void)setTextViewFrame{
NSDictionary *textDict = @{NSFontAttributeName:KtextFont};
CGRect textFrame = [self.status.text boundingRectWithSize:CGSizeMake(300, MAXFLOAT) options: NSStringDrawingUsesLineFragmentOrigin attributes:textDict context:nil];
textFrame.origin.x = KPading;
textFrame.origin.y = CGRectGetMaxY(self.iconViewFrame)+KPading ;
_textViewFrame = textFrame;
}
/** 计算配图的frame*/
- (void)setPictureViewFrame{
self.pictureViewFrame = CGRectMake(KPading,CGRectGetMaxY(self.textViewFrame)+KPading, 100, 100);
}
/** 计算cell的行高*/
- (void)setCellHeight{
CGFloat picHeight = (self.status.picture.length >0) ? KPading+CGRectGetHeight(self.pictureViewFrame): 0;
_cellHeight = CGRectGetHeight(self.iconViewFrame)+CGRectGetHeight(self.textViewFrame)+picHeight+2*KPading;
}
//实例化frame模型
- (instancetype)initWithStatus:(HSStatus *)status{
//KVC
self = [super init];//初始化父类属性
if (self) {
//初始化自身属性
[self setStatus:status];
}
return self;
}
//实例化frame模型
+ (instancetype)statusFrameWithStatus:(HSStatus *)status{
return [[self alloc]initWithStatus:status];
}
//返回frame模型数组
+ (NSArray *)statusFrames{
NSMutableArray *tmpArrayM = [NSMutableArray array];
//解析plist
NSArray *arrayDict = [HSStatus statuses];
for (HSStatus *status in arrayDict) {
[tmpArrayM addObject:[self statusFrameWithStatus:status]];
}
return tmpArrayM;
}
@end
III 其他
3.1 Xcode编辑技巧
-
自定义视图的分割线:使用UIView,高度为1,设置下背景颜色即可)
-
自定义的代码块文件 ~/Library/Developer/Xcode/UserData/CodeSnippets--换新电脑,直接替换文件夹中的内容即可。
3.2 错误分析
1.CUICatalog: Invalid asset name supplied: (null)
_pictureImage = [UIImage imageNamed:self.picture];//self.picture为nil,将会报错CUICatalog: Invalid asset name supplied: (null)
see also
🍅 联系作者: iOS逆向(公号:iosrev)
🍅 作者简介:CSDN 博客专家认证🏆丨全站 Top 50、华为云云享专家认证🏆、iOS逆向公号号主
🍅 简历模板、技术互助。关注我,都给你。