效果图:
分析:从plist文件中读取数据源,plist最外层是一个Array,Array中存放的是字典,每个字典存放的key值并不完全相同。
一、单元格复用问题
1、首先读取数据源,建立数据模型,这里我只创建了一个数据模型,包含plist中所有的key值所对应的属性。
2、创建tableView,同时定制Cell,
根据category,可以分成四种单元格,在tableView创建单元格时创建4种代码如下:
1 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 2 { 3 4 CustomCell * appcustomCell = [tableView dequeueReusableCellWithIdentifier:@"appcustomCell"]; 5 6 if (!appcustomCell) { 7 appcustomCell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"appcustomCell"]; 8 NSLog(@"appcustomCell"); 9 } 10 11 CustomCell * listcustomCell = [tableView dequeueReusableCellWithIdentifier:@"listcustomCell"]; 12 13 if (!listcustomCell) { 14 listcustomCell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"listcustomCell"]; 15 NSLog(@"listcustomCell"); 16 } 17 18 CustomCell * origincustomCell = [tableView dequeueReusableCellWithIdentifier:@"origincustomCell"]; 19 20 if (!origincustomCell) { 21 origincustomCell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"news"]; 22 NSLog(@"origincustomCell"); 23 } 24 25 CustomCell * largecustomCell = [tableView dequeueReusableCellWithIdentifier:@"largecustomCell"]; 26 27 if (!largecustomCell) { 28 largecustomCell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"largecustomCell"]; 29 NSLog(@"largecustomCell"); 30 } 31 32 33 34 Model *model = [_dataSource objectAtIndex:indexPath.row]; 35 36 37 if ([model.category isEqualToString:@"list"]) { 38 listcustomCell.category = model.category; 39 listcustomCell.message = model.title ; 40 41 listcustomCell.imageNames = model.pics; 42 listcustomCell.source = model.source; 43 listcustomCell.time = model.time ; 44 return listcustomCell; 45 46 47 } 48 if ([model.category isEqualToString:@"origin"]) { 49 origincustomCell.category = model.category; 50 origincustomCell.message = model.title ; 51 52 origincustomCell.picture = model.picture ; 53 origincustomCell.source = model.source; 54 return origincustomCell; 55 } 56 57 if ([model.category isEqualToString:@"large"]) { 58 largecustomCell.category = model.category; 59 largecustomCell.message = model.title ; 60 61 largecustomCell.picture = model.picture; 62 largecustomCell.source = model.source; 63 largecustomCell.time = model.time; 64 return largecustomCell; 65 } 66 67 if ([model.category isEqualToString:@"app"]) { 68 appcustomCell.category = model.category; 69 appcustomCell.message = model.title ; 70 71 appcustomCell.icon = model.icon; 72 appcustomCell.appname = model.appname; 73 return appcustomCell; 74 } 75 return nil; 76 }
上面是防止复用时出错的办法
二、题目的重点:Cell动态调整高度
1、动态调整单元格的高度,那么肯定要调用tableView代理的一个方法,换回单元格高度,代码如下: 1 -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
2 { 3 //用来返回每一行的高度 4 //只有确定了数据,能才知道行的高度,所以在这先要去取得数据 5 Model * model = [_dataSource objectAtIndex:indexPath.row]; 6 //因为计算行高这个事是cell来计算的,所以还得需要创建一个cell对象 7 //为了去避免在计算行高时,开辟多个cell对象空间,造成资源的浪费 8 //所以在这里,要实现cell的复用 9 cell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"xx"]; 10 if (!cell) { 11 cell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"xx"]; 12 13 } 14 15 //将数据赋给cell,然后cell去计算行高 16 //这里说的计算是,数据赋值给Cell的时候,都要调用定制Cell类中的对应属性的set方法,在set方法中返回rowHight,rowHight也是Cell的属性 17 //这样按照单元格中的各个控件的顺序返回相应的高度,一定要注意控件的排放顺序 18 cell.category = model.category; 19 cell.message = model.title ; 20 if ([model.category isEqualToString:@"list"]) { 21 cell.imageNames = model.pics; 22 cell.source = model.source; 23 cell.time = model.time ; 24 25 26 } 27 if ([model.category isEqualToString:@"origin"]) { 28 cell.picture = model.picture ; 29 cell.source = model.source; 30 } 31 32 if ([model.category isEqualToString:@"large"]) { 33 cell.picture = model.picture; 34 cell.source = model.source; 35 cell.time = model.time; 36 } 37 38 if ([model.category isEqualToString:@"app"]) { 39 cell.icon = model.icon; 40 cell.appname = model.appname; 41 42 } 43 44 45 46 47 //因为cell里赋值后可以利用赋值内容来计算出行高,所以在赋值后,直接返回行高 48 return cell.rowHeight; 49 50 51 }
2、在定制单元格中返回该控件的高度,通过重写控件的set方法确定该控件是否显示,代码:
1 -(void)setSource:(NSString *)source 2 { 3 4 _source = source; 5 if (![_category isEqualToString:@"app"]) { 6 sourceLabel.hidden = NO; 7 sourceLabel.text = _source; 8 sourceLabel.frame = CGRectMake(10, _rowHeight, 100, 15); 9 }
//消息所有的工作做完后,要重新云计算一下行高
//下面这个方法是用来取一个控件的最大y值
//这个值是从原点y坐标 + 控件高度
//实际行高等于 上个值 再加 5
10 _rowHeight = CGRectGetMaxY(sourceLabel.frame) + 5; 11 12 }
在Cell定制类中首先加一个Label控件,设置为隐藏,因为不知道这个控件是不是真的需要,所以当调用控件对应内容的set方法时时肯定要使用这个控件了,将控件隐藏属性设置为NO,这里需要重新为控件布局。因为在这个控件之前不知道已有的控件占了多少高度,这里通过rowHight属性获得前面的高度,然后返回时加上自己的高度,加上5是为了调整控件之间的距离吧.
3、不得不说的是label中内容很多时怎么计算其高度,
1 -(void)setMessage:(NSString *)message 2 { 3 4 //判断一下有没有消息 5 if (message.length == 0) { 6 //如果没有消息 7 messageLabel.hidden = YES; 8 _rowHeight = 60.0f; 9 return; 10 } 11 //如果有消息 12 //将参数消息赋给属性 13 _message = message; 14 //有消息要显示,那么就将控件显示出来 15 messageLabel.hidden = NO; 16 //求出这条消息实际占用的高度 17 //下面这个方法用来求出消息内容实际占的size 18 // message sizeWithFont:(UIFont *) 19 CGSize size = [message boundingRectWithSize:CGSizeMake(255, 9999) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15]} context:nil].size; 20 //根据计算过后的消息所占的宽高,来调整messageLabel的frame 21 if ([_category isEqualToString:@"origin"]) { 22 messageLabel.frame = CGRectMake(5, 20, 180, size.height); 23 } 24 else 25 { 26 messageLabel.frame = CGRectMake(5, 5, 310, size.height); 27 } 28 29 //给消息控件赋值 30 messageLabel.text = message; 31 32 //消息所有的工作做完后,要重新云计算一下行高 33 //下面这个方法是用来取一个控件的最大y值 34 //这个值是从原点y坐标 + 控件高度 35 //实际行高等于 上个值 再加 5 36 _rowHeight = CGRectGetMaxY(messageLabel.frame) + 5; 37 38 39 }
最重要的应该是这个方法了:
CGSize size = [message boundingRectWithSize:CGSizeMake(255, 9999) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15]} context:nil].size;不太清除是什么意思,只知道根据message字体大小计算出了一个CGSize, 总结:前面说了要做出的效果,然后说了不同单单元格解决复用重叠的方法,最后说了自动调整高度。
时间: 2024-09-29 17:10:29