项目中有一个页面为活动详情页,其中活动的相关内容放置于一个底色为白色的view中,其余的背景色为灰色。效果完成图以下数组
由于内容分为活动时间、金额、规则等且有横线隔开,因此决定用 tableview 来画,建立一个 cell 文件添加内容,再建立一个 controller 在内建立 tableview 承载便可。bash
内容因为分类不一样放置于各个 cell 中。然而其中文字内容长度均不一样且在后续使用中一定会改变。 cell 的高度根据内容自适应由app
//row高自适应
_tableView.rowHeight = UITableViewAutomaticDimension;
//给一个预估值,当计算不出时会默认使用此高度
_tableView.estimatedRowHeight = 100;
复制代码
便可设置。布局
先这样想:计算每个 cell 的高度,再把它们各自高度的值传至 controller 中进行累加。ui
首先须要传值,选择用 ReactiveObjc(即RAC) 来进行传值:atom
在 cell.h 中声明 subject :spa
@property (nonatomic, strong) RACSubject *subject;
复制代码
cell.m 中懒加载建立:代理
- (RACSubject *)subject{
if (!_subject) {
_subject = [RACSubject subject];
}
return _subject;
}
复制代码
在建立 cell 的代理中的语句code
ABLaborActivityDetailViewCell *cell = [tableView dequeueReusableCellWithIdentifier:Identifier];
复制代码
一开始,在 cell.m 中的 setLayout 布局方法中,是先走一遍及局,建立控件的,在执行至 cell.index = indexPath.row; 时,才会走 setIndex 方法,给控件内容赋值。cdn
因此要确认什么时候开始传值,咱们要声明一个全局变量
BOOL _isLayout;//状态开关
复制代码
并在布局方法 - (void)setLayout 中一开始令初始状态为 NO
_isLayout = NO;
复制代码
在 setIndex 赋值方法中:
- (void)setIndex:(NSInteger)index{
self.titleLabel.text = self.dataArray[index][@"title"];
self.detailLabel.text = self.dataArray[index][@"detail"];
//经过 index 和数组给 cell 内容赋值时,让开关为 YES ,走几回由咱们建立的数组决定,每一次都会走 layoutIfNeeded 方法。
_isLayout = YES;
//调用 layoutSubviews 方法
[self layoutIfNeeded];
}
复制代码
也就是走完一次 setLayout 建立空控件后,让 _isLayout = YES;
此时才开始传值,此方法添加在 setLayout 方法末尾:
- (void)layoutSubviews{
[super layoutSubviews];
//每次信号为 YES ,都会经过 RAC 传出 cell 的高度 self.size.height 。
if (_isLayout == YES) {
[self.subject sendNext:@(self.size.height)];
//打印 cell高检查
NSLog(@"CELL高=%f",self.size.height);
}
复制代码
执行结果打印 cell 高以下,前10行,均为计算空控件赋值前的初始高度(44)-> 获得内容后的高度,循环5次(由于有5个 cell ),后5行即各cell最终高度。
function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=44.000000
function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=50.000000
function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=44.000000
function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=50.000000
function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=44.000000
function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=50.000000
function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=44.000000
function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=81.000000
function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=44.000000
function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=96.500000
function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=50.000000
function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=50.000000
function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=50.000000
function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=81.000000
function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=96.500000
复制代码
这样在 cell 内传值结束, cell 内代码也结束啦
须要建立全局变量接收传过来的 cell 高:
{
CGFloat _tableViewHeight;//接收cell的高度
BOOL _isEnd;//刷新开关
}
复制代码
这里有个 BOOL 变量,由于在接收值刷新 tableview 的时候,会出现死循环,为了解决死循环,需给一个开关进行判断什么时候刷新中止。
在 viewDidLoad 中给两个全局变量以初始状态:
_tableViewHeight = 0;//给初始高度
_isEnd = NO;//给初始状态
复制代码
在 cell 内容代理中:
weakifyySelf;
[cell.subject subscribeNext:^(NSNumber *x) {
stronggSelf;
//接收cell值并累加
_tableViewHeight = _tableViewHeight + [x floatValue];
//在进行到第5行时,而且开关处于 NO 状态,则执行开关切换为YES,防止再次刷新;给 tableview 范围,
并刷新数据,令其显示正确范围,高度计算完毕需按实际状况进行调整,这里 +50 使显示彻底
if (indexPath.row == 4 && _isEnd == NO) {
_isEnd = YES;
self.tableView.size = CGSizeMake(SCREEN_WIDTH - 30, _tableViewHeight+50);
[self.tableView reloadData];
}
}];
复制代码
这里再贴一遍最终效果:
活动详情内容,须要给一个最大宽度,考虑适配,应该计算,而不是给肯定值,这里例子为(左侧例如“挑战时间”这些title我是给了控件宽度的,计算时要减去):
//自动换行
_detailLabel.numberOfLines = 0;
//3一、33为左右边距,67为左侧title长度
_detailLabel.preferredMaxLayoutWidth = SCREEN_WIDTH - 31-33 - 67;
复制代码
- 李鸿:广州芦苇科技 APP 团队 iOS 开发工程师
- 咱们正在招募小伙伴,有兴趣的小伙伴能够把简历发到 app@talkmoney.cn,备注:来自掘金社区
- 详情能够戳这里--> 广州芦苇信息科技