技术的乐趣在于分享,欢迎多多交流,多多沟通。
全部博文(877)
分类: iOS平台
2015-12-07 18:24:43
往往在开发iPhone的应用过程中用得最多的应该算是UITableVIew了,凭着IOS给UITableView赋予了这种灵活的框架结构,让它不管在显示列表方面还是在排版方面都有着一定的优势。虽然UITableView功能强大,但是对于一些复杂的应用需求在开发的过程中会出现一些问题,如动态改变UITableView显示的Cell高度就是其中之一
其实想要改变UITableView的Cell高度并不难,UITableView带有一个rowHeight属性,使用他就可以改变高度了。但是这样的改变是把所有的Cell的高度都统一改变了。如果存在不同的内容就有不同的Cell高度,那么这时候rowHeight显得力不从心了。不过iOS似乎考虑到了这一点,在UITableView的UITableViewDelegate委托下有一个委托方法可以动态地指定Cell的高度,其声明如下:
- (CGFloat)tableView:( *)tableView heightForRowAtIndexPath:( *)indexPath
此委托方法就可以根据索引位置indexPath来控制返回的Cell高度。可能有人会认为我实现这个委托就可以实现我上面说的效果了吗?是用到这个委托没错,但是使用这个委托时是会存在一些问题的,下面的内容就是要针对这些问题提出我在实际的开发工作中的处理方法,希望通过共享这些思路能够让童鞋们少走点弯路。
其实主要的问题是heightForRowAtIndexPath这个委托的调用时机是早于cellForRowAtIndexPath这个委托方法的(此方法在UITableViewDataSource中定义)我们都知道cellForRowAtIndexPath是用于返回UITableViewCell的方法。那么问题就在这里了,如果我cell还没返回,那我之前怎么能够在heightForRowAtIndexPath中得到cell的高度呢?也许有人会说:我在返回Cell之后重新刷新指定的Cell就能够得到高度了。但其实这个实践起来是很困难的。而还有一点要注意的是在heightForRowAtIndexPath是不能使用UITableView的cellForRowAtIndexPath:返回Cell对象的。否则会导致无限级递归调用引发的堆栈溢出 。原因是调用此方法会触发heightForRowAtIndexPath委托方法。但是要调用也是可以的。解决方法就是先把delegate为空,等获取到Cell后再重新赋值。如:
tableView.delegate=nil;
UITableViewCell *cell=[tableView cellForRowAtIndexPath:indexPath];
tableView.delegate=self;
那么有什么办法可以更加方便实现呢? 我们传统的做法都是在 cellForRowAtIndexPat中排版或者继承UITableViewCell进行排版。而这个也不可避免,但是对于这种动态变更高度的处理,本人认为最好不要直接在cellForRowAtIndexPat中进行排版,应该继承UITableViewCell生成子类,然后在子类里面进行排版工作。因为这跟下面说的解决方法有关。
先说说本人的解决思路吧,其实办法很简单,通过样本Cell来计算高度即可。也就是说我在定义Cell的子类后,在包含UITableView的控制器类或者视图类中定义一个Cell子类的属性,此属性就是专门用于在heightForRowAtIndexPath中计算Cell高度用。这样就能够正确地返回Cell的高度了。先来看看Cell的子类定义:
@interface DemoCell : NSObject{
UILabel *_content;
}
-(CGFloat)contentHeight;
-(void)setContent:(NSString *)content;
@end;
从上面的DemoCell来看其带有一个UILabel对象,这个Cell就是要根据UILabel的内容动态更改高度。其中contentHeight方法是返回Cell的高度。setContent是设置UILabel的内容并计算UILabel的高度。此类很简单要做的就是这样这些操作。然后我们在控制器中定义一个样本Cell专门用于计算Cell的高度。代码如下:
#import "DemoCell.h"
@interface DemoViewController : UIViewController
UITableView *_tableView;
DemoCell *_sampleCell;
NSArray *_listData;
}
@end;
其中部分实现代码如下:
- (CGFloat)tableView:( *)tableView heightForRowAtIndexPath:( *)indexPath{
//在此使用样本Cell计算高度。
NSString *content=[_listData objectAtIndex:indexPath.row];
[_sampleCell setContent:content];
return [_sampleCell contentHeight];
}
- ( *)tableView:( *)tableView cellForRowAtIndexPath:( *)indexPath{
static NSString *cellId=@"DemoCell";
DemoCell *cell=(DemoCell *)[tableView dequeueReusableCellWithIdentifier:cellId];
if(cell==nil){
cell=[[[DemoCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId] autorelease];
}
[cell setContent:[_listData objectAtIndex indexPath:indexPath.row]];
return cell;
}
到此为止我们已经顺利地展示了如何动态变更Cell的高度。只要内容变更我们调用UITableView的reloadData方法就可以刷新整个列表了。Cell如何计算高度本人没有列出来,因为不同的需求导致这部分的实现会不一样。这里只是把思路给大家交代清楚。具体的实现还是要各位童鞋们自己动手操作。