今天看到了@SUNNYXX大神的博客,其中有一篇优化UITableViewCell高度计算的那些事讲了FDTemplateLayoutCell,并且与其它两个布局方法做了对比,好处显而易见(最低适配iOS6、运行效率更高)。分别是iOS6的-systemLayoutSizeFittingSize:
的API和iOS8的self-sizing cell
(estimatedRowHeight、UITableViewAutomaticDimension)方法。上面两个方法之前也在博客中写过。
作为一个开发还没到一年的人,@SUNNYXX大神、喵神等都是学习的榜样,各种崇拜。
不同与Xib+FDTemplateLayoutCell的布局方法,我用的是Masonry+FDTemplateLayoutCell,运行时总是有很多约束冲突,对于原因暂时还不知道。
ViewController
#import "ViewController.h"
#import "CustomCell.h"
#import "Masonry.h"
#import "UITableView+FDTemplateLayoutCell.h"
#import "CustomModel.h"
#import "MHPrettyDate.h"
typedef NS_ENUM(NSUInteger, HTSimulatedCacheModel) {
HTSimulatedCacheModelNone=0,
HTSimulatedCacheModelCacheByIndexpath,
HTSimulatedCacheModelCacheByKey
};
#define COMMON_COLOR [UIColor colorWithRed:0/255.0f green:0/255.0f blue:107/255.0f alpha:1.0]
#define REUSEID @"CustomCellId"
@interface ViewController () <UITableViewDataSource,UITableViewDelegate,UIActionSheetDelegate>
//@property(nonatomic,retain) UIRefreshControl *kRefreshControl;
@property(nonatomic,retain) UISegmentedControl *kSegmentedControl;
@property(nonatomic,retain) UITableView *kTabelView;
@property(nonatomic,retain) NSMutableArray *kDataSource;
@end
@implementation ViewController
#pragma mark - Life Cycle
- (void)viewDidLoad {
[super viewDidLoad];
[self uiConfig];
[self buildTestDataThen:^{
[self.kTabelView reloadData];
NSLog(@"count=%ld",self.kDataSource.count);
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#pragma mark - UITableViewDataSource
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return [self.kDataSource count];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
NSArray *tempArr=[self.kDataSource objectAtIndex:section];
return [tempArr count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
CustomCell *cell=[tableView dequeueReusableCellWithIdentifier:REUSEID forIndexPath:indexPath];
[self configureCell:cell atIndexpath:indexPath];
return cell;
}
-(void)configureCell:(CustomCell *)cell atIndexpath:(NSIndexPath *)indexPath{
cell.fd_enforceFrameLayout=NO;
if (indexPath.row%2==0) {
cell.accessoryType=UITableViewCellAccessoryDisclosureIndicator;
}else{
cell.accessoryType=UITableViewCellAccessoryCheckmark;
}
NSArray *tempArr=[self.kDataSource objectAtIndex:indexPath.section];
[cell setModel:[tempArr objectAtIndex:indexPath.row]];
}
#pragma mark - UITableViewDelegate
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
HTSimulatedCacheModel model=self.kSegmentedControl.selectedSegmentIndex;
switch (model) {
case HTSimulatedCacheModelNone:
return [tableView fd_heightForCellWithIdentifier:REUSEID configuration:^(id cell) {
[self configureCell:cell atIndexpath:indexPath];
}];
case HTSimulatedCacheModelCacheByIndexpath:
return [tableView fd_heightForCellWithIdentifier:REUSEID cacheByIndexPath:indexPath configuration:^(id cell) {
[self configureCell:cell atIndexpath:indexPath];
}];
case HTSimulatedCacheModelCacheByKey:
return [tableView fd_heightForCellWithIdentifier:REUSEID cacheByKey:[NSString stringWithFormat:@"key:%ld",indexPath.row] configuration:^(id cell) {
[self configureCell:cell atIndexpath:indexPath];
}];
default:
break;
}
}
//-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
// if (editingStyle==UITableViewCellEditingStyleDelete) {
// NSMutableArray *tempArr=[self.kDataSource objectAtIndex:indexPath.section];
// [tempArr removeObjectAtIndex:indexPath.row];
// [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
// }
//}
//
//-(NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath{
// return @"删除";
//}
//或者
- (nullable NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewRowAction *action=[UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"删除" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
NSMutableArray *tempArr=[self.kDataSource objectAtIndex:indexPath.section];
[tempArr removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}];
action.backgroundColor=COMMON_COLOR;
return @[action];
}
#pragma mark - UIActionSheetDelegate
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
SEL selectors[]={
@selector(insertRow),
@selector(insertSection),
@selector(deleteSection)
};
if (buttonIndex<sizeof(selectors)/sizeof(SEL)) {
void(*imp)(id,SEL)=(typeof(imp))[self methodForSelector:selectors[buttonIndex]];
imp(self,selectors[buttonIndex]);
}
}
#pragma mark - Private Method
//模拟异步请求 然后回调
-(void)buildTestDataThen:(void(^)(void))then{
[self.kDataSource removeAllObjects];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSMutableArray *tempArr=[[NSMutableArray alloc] init];
for (int i=0; i<20; i++) {
[tempArr addObject:[self getRandomModelWithIndex:i]];
}
[self.kDataSource addObject:tempArr];
//回调
dispatch_sync(dispatch_get_main_queue(), ^{
!then ? :then();
});
});
}
-(CustomModel *)getRandomModelWithIndex:(int)index{
CustomModel *model=[[CustomModel alloc] init];
model.kTitle=[NSString stringWithFormat:@"Title:%d",index];
model.kImgName=[NSString stringWithFormat:@"%d.png",arc4random()%6+1];
model.kContent=[self getRandomContent];
model.kDataStr=[MHPrettyDate prettyDateFromDate:[NSDate date] withFormat:MHPrettyDateFormatWithTime];
model.kAuthor=[NSString stringWithFormat:@"Author:%d",index];
return model;
}
-(void)uiConfig{
self.view.backgroundColor=[UIColor lightTextColor];
self.title=@"CellLayoutDemo";
UIBarButtonItem *rightItem=[[UIBarButtonItem alloc] initWithTitle:@"Action" style:UIBarButtonItemStylePlain target:self action:@selector(rightItemAction)];
self.navigationItem.rightBarButtonItem=rightItem;
self.edgesForExtendedLayout=UIRectEdgeNone;
[self.view addSubview:self.kTabelView];
self.kTabelView.tableHeaderView=self.kSegmentedControl;
[self.kTabelView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.view.mas_top).offset(10);
make.left.right.bottom.equalTo(self.view);
}];
}
-(NSString *)getRandomContent{
NSInteger num=arc4random()%10+1;
NSMutableString *mutString=[[NSMutableString alloc] init];
while (num>0) {
[mutString appendString:@"不要假设我知道,一切也都是为我而做,为何这么伟大."];
num-=1;
}
return mutString;
}
#pragma mark - Action Method
-(void)rightItemAction{
UIActionSheet *actionSheet=[[UIActionSheet alloc ] initWithTitle:@"Actions" delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"Insert a row",@"Insert a section", @"Delete a section",nil];
[actionSheet showInView:self.view];
}
-(void)insertRow{
if ([self.kDataSource count]==0) {
[self insertSection];
}else{
NSMutableArray *tempArr=[self.kDataSource firstObject];
[tempArr insertObject:[self getRandomModelWithIndex:0] atIndex:0];
NSIndexPath *indexPath=[NSIndexPath indexPathForRow:0 inSection:0];
[self.kTabelView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
-(void)insertSection{
NSMutableArray *tempArr=[[NSMutableArray alloc] init];
[tempArr addObject:[self getRandomModelWithIndex:0]];
[self.kDataSource insertObject:tempArr atIndex:0];
[self.kTabelView insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationAutomatic];
}
-(void)deleteSection{
if ([self.kDataSource count]>0) {
[self.kDataSource removeObjectAtIndex:0];
[self.kTabelView deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
#pragma mark - Lazy Method
//-(UIRefreshControl *)kRefreshControl{
// if (_kRefreshControl==nil) {
// _kRefreshControl=[[UIRefreshControl alloc] init];
// _kRefreshControl.tintColor=COMMON_COLOR;
// }
// return _kRefreshControl;
//}
-(UISegmentedControl *)kSegmentedControl{
if (_kSegmentedControl==nil) {
_kSegmentedControl=[[UISegmentedControl alloc] initWithItems:@[@"No Cache",@"IndexPath Cache",@"Key Cache"]];
_kSegmentedControl.frame=CGRectMake(20, 0, self.kTabelView.frame.size.width-40, 30);
_kSegmentedControl.tintColor=COMMON_COLOR;
_kSegmentedControl.selectedSegmentIndex=0;
}
return _kSegmentedControl;
}
-(UITableView *)kTabelView{
if (_kTabelView==nil) {
_kTabelView=[[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
_kTabelView.backgroundColor=[UIColor lightGrayColor];
_kTabelView.tableFooterView=[UIView new];
_kTabelView.dataSource=self;
_kTabelView.delegate=self;
[_kTabelView registerClass:[CustomCell class] forCellReuseIdentifier:REUSEID];
// _kTabelView.estimatedRowHeight=200;
// _kTabelView.rowHeight=UITableViewAutomaticDimension;
}
return _kTabelView;
}
-(NSMutableArray *)kDataSource{
if (_kDataSource==nil) {
_kDataSource=[[NSMutableArray alloc] init];
}
return _kDataSource;
}
@end
CustomCell
#import "CustomCell.h"
#import "Masonry.h"
#define COMMON_COLOR [UIColor colorWithRed:0/255.0f green:0/255.0f blue:107/255.0f alpha:1.0]
#define CUSTOM_LIGHTGRAY_COLOR [UIColor colorWithRed:85/255.0f green:85/255.0f blue:85/255.0f alpha:1.0]
#define CUSTOM_BLUE_COLOR [UIColor colorWithRed:140/255.0f green:170/255.0f blue:228/255.0f alpha:1.0]
@interface CustomCell ()
@property(nonatomic,retain) UILabel *kTitleLabel,*kContentLabel,*kAuthorLabel,*kDateLabel;
@property(nonatomic,retain) UIImageView *kIconView;
@end
@implementation CustomCell
#pragma mark - Override
-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
self=[super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self uiConfig];
}
return self;
}
#pragma mark - Public Method
-(void)setModel:(CustomModel *)model{
self.kTitleLabel.text=model.kTitle;
self.kContentLabel.text=model.kContent;
self.kAuthorLabel.text=model.kAuthor;
self.kDateLabel.text=model.kDataStr;
self.kIconView.image=[UIImage imageNamed:model.kImgName];
}
#pragma mark - Private Method
-(void)uiConfig{
self.selectionStyle=UITableViewCellSelectionStyleNone;
[self.contentView addSubview:self.kTitleLabel];
[self.contentView addSubview:self.kContentLabel];
[self.contentView addSubview:self.kIconView];
[self.contentView addSubview:self.kAuthorLabel];
[self.contentView addSubview:self.kDateLabel];
[self.kTitleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.contentView.mas_top).offset(10);
make.left.equalTo(self.contentView.mas_left).offset(10);
make.width.mas_equalTo(100);
make.height.mas_equalTo(15);
}];
[self.kContentLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.kTitleLabel.mas_bottom).offset(10);
make.left.equalTo(self.contentView.mas_left).offset(10);
make.right.equalTo(self.contentView.mas_right).offset(-15);
}];
// [self.kContentLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
// [self.kContentLabel setContentHuggingPriority:UILayoutConstraintAxisVertical forAxis:UILayoutConstraintAxisVertical];
[self.kIconView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.kContentLabel.mas_bottom).offset(10);
make.left.equalTo(self.contentView.mas_left).offset(10);
make.right.lessThanOrEqualTo(self.contentView.mas_right).offset(-16);
make.bottom.equalTo(self.kAuthorLabel.mas_bottom).offset(-20);
}];
[self.kAuthorLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(self.contentView.mas_bottom).offset(-10);
make.left.equalTo(self.contentView.mas_left).offset(10);
make.width.mas_equalTo(100);
make.height.mas_equalTo(15);
}];
[self.kDateLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.height.equalTo(self.kAuthorLabel);
make.right.equalTo(self.contentView.mas_right).offset(-20);
make.width.mas_equalTo(60);
}];
}
#pragma mark - Private Method
-(UILabel *)kTitleLabel{
if (_kTitleLabel==nil) {
_kTitleLabel=[[UILabel alloc] init];
_kTitleLabel.textColor=COMMON_COLOR;
_kTitleLabel.font=[UIFont boldSystemFontOfSize:16];
}
return _kTitleLabel;
}
-(UILabel *)kContentLabel{
if (_kContentLabel==nil) {
_kContentLabel=[[UILabel alloc] init];
_kContentLabel.numberOfLines=0;
_kContentLabel.lineBreakMode=NSLineBreakByWordWrapping;
_kContentLabel.textColor=CUSTOM_LIGHTGRAY_COLOR;
_kContentLabel.font=[UIFont systemFontOfSize:14];
}
return _kContentLabel;
}
-(UILabel *)kAuthorLabel{
if (_kAuthorLabel==nil) {
_kAuthorLabel=[[UILabel alloc] init];
_kAuthorLabel.textColor=[UIColor lightGrayColor];
_kAuthorLabel.font=[UIFont systemFontOfSize:14];
}
return _kAuthorLabel;
}
-(UILabel *)kDateLabel{
if (_kDateLabel==nil) {
_kDateLabel=[[UILabel alloc] init];
_kDateLabel.textColor=CUSTOM_BLUE_COLOR;
_kDateLabel.font=[UIFont systemFontOfSize:14];
_kDateLabel.textAlignment=NSTextAlignmentRight;
}
return _kDateLabel;
}
-(UIImageView *)kIconView{
if (_kIconView==nil) {
_kIconView=[[UIImageView alloc] init];
_kIconView.contentMode=UIViewContentModeCenter;
_kIconView.clipsToBounds=YES;
}
return _kIconView;
}
@end
CustomModel
#import
@interface CustomModel : NSObject
@property(nonatomic,copy) NSString *kTitle,*kImgName,*kContent,*kDataStr,*kAuthor;
@end