首页 > 代码库 > 05---MVC模式下动态调整Cell高度三部曲
05---MVC模式下动态调整Cell高度三部曲
动态调整Cell高度三部曲
我们在做项目开发的过程中经常会遇到每一个cell的高度及cell的子控件的显示个数不同,以我最近开发的微格为例,讲解一下MVC模式动态的调整Cell宽高的三部曲
1>.自定义Cell,重写- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier方法 在此方法中添加所有的可能显示的子控件
子控件的frame通过构建的cellFrame模型进行设置 - (void)setCellFrame:(cellFrame *)cellFrame (顺便设置文字,图片等信息)
#import <UIKit/UIKit.h>@class StatusCellFrame;@interface StatusCell : UITableViewCell{ UIImageView *_icon; // 头像 UILabel *_screenName; // 昵称 UILabel *_time; // 时间 UILabel *_source; // 来源 UILabel *_text; // 内容 UIImageView *_image; // 配图 UIImageView *_retweeted; // 被转发微博的父控件 UILabel *_retweetedScreenName; // 被转发微博作者的昵称 UILabel *_retweetedText; // 被转发微博的内容 UIImageView *_retweetedImage; // 被转发微博的配图}// 每一个微博Cell都含有statusCellFrame这个模型对象的属性@property (nonatomic, strong) StatusCellFrame *statusCellFrame;@end// MVC设计模式 : 一般都是设计一个模型Model 在视图View中拥有这个Model的实例
//// StatusCell.m// 新浪微博控//// Created by WHB on 14-7-22.// Copyright (c) 2014年 whblap. All rights reserved.//#import "StatusCell.h"#import "StatusCellFrame.h"#import "Status.h"#import "UIImageView+WebCache.h" #import "User.h"@implementation StatusCell- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{ self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { // 1.添加微博本身的子控件 [self addAllSubviews]; // 2.添加被转发微博的子控件 [self addReweetedAllSubviews]; } return self;}#pragma mark 添加微博本身的子控件- (void)addAllSubviews{ // 1.头像 _icon = [[UIImageView alloc] init]; [self.contentView addSubview:_icon]; // 2.昵称 _screenName = [[UILabel alloc] init]; _screenName.font = kScreenNameFont; [self.contentView addSubview:_screenName]; // 3.时间 _time = [[UILabel alloc] init]; _time.font = kTimeFont; [self.contentView addSubview:_time]; // 4.来源 _source = [[UILabel alloc] init]; _source.font = kSourceFont; [self.contentView addSubview:_source]; // 5.内容 _text = [[UILabel alloc] init]; _text.numberOfLines = 0; _text.font = kTextFont; [self.contentView addSubview:_text]; // 6.配图 _image = [[UIImageView alloc] init]; [self.contentView addSubview:_image];}#pragma mark 被转发微博的子控件- (void)addReweetedAllSubviews{ // 1.被转发微博的父控件 _retweeted = [[UIImageView alloc] init]; [self.contentView addSubview:_retweeted]; // 2.被转发微博的昵称 _retweetedScreenName = [[UILabel alloc] init]; _retweetedScreenName.font = kRetweetedScreenNameFont; [_retweeted addSubview:_retweetedScreenName]; // 3.被转发微博的内容 _retweetedText = [[UILabel alloc] init]; _retweetedText.numberOfLines = 0; _retweetedText.font = kRetweetedTextFont; [_retweeted addSubview:_retweetedText]; // 4.被转发微博的配图 _retweetedImage = [[UIImageView alloc] init]; [_retweeted addSubview:_retweetedImage];}- (void)setStatusCellFrame:(StatusCellFrame *)statusCellFrame{ _statusCellFrame = statusCellFrame; Status *s = statusCellFrame.status; // 1.头像 _icon.frame = statusCellFrame.iconFrame; [_icon setImageWithURL:[NSURL URLWithString:s.user.profileImageUrl] placeholderImage:[UIImage imageNamed:@"Icon.png"] options:SDWebImageRetryFailed | SDWebImageLowPriority]; // 2.昵称 _screenName.frame = statusCellFrame.screenNameFrame; _screenName.text = s.user.screenName; // 3.时间 _time.frame = statusCellFrame.timeFrame; _time.text = s.createdAt; // 4.来源 _source.frame = statusCellFrame.sourceFrame; _source.text = s.source; // 5.内容 _text.frame = statusCellFrame.textFrame; _text.text = s.text; // 6.配图 if (s.picUrls.count) { _image.hidden = NO; _image.frame = statusCellFrame.imageFrame; // MyLog(@"pic---%@", s.picUrls); NSString *imageStr = s.picUrls[0][@"thumbnail_pic"]; NSURL *imageURL = [NSURL URLWithString:imageStr]; [_image setImageWithURL:imageURL placeholderImage:[UIImage imageNamed:@"Icon.png"] options:SDWebImageLowPriority | SDWebImageRetryFailed]; //#warning 配图的图片 } else { _image.hidden = YES; } // 7.被转发微博 if (s.retweetedStatus) { _retweeted.hidden = NO; _retweeted.frame = statusCellFrame.retweetedFrame; // 8.昵称 _retweetedScreenName.frame = statusCellFrame.retweetedScreenNameFrame; _retweetedScreenName.text = s.retweetedStatus.user.screenName; // 9.内容 _retweetedText.frame = statusCellFrame.retweetedTextFrame; _retweetedText.text = s.retweetedStatus.text; // 10.配图 if (s.retweetedStatus.picUrls.count) { _retweetedImage.hidden = NO; _retweetedImage.frame = statusCellFrame.retweetedImageFrame; [_retweetedImage setImageWithURL:[NSURL URLWithString:s.retweetedStatus.picUrls[0][@"thumbnail_pic"]] placeholderImage:[UIImage imageNamed:@"Icon.png"] options:SDWebImageRetryFailed | SDWebImageLowPriority]; } else { _retweetedImage.hidden = YES; } } else { _retweeted.hidden = YES; } }@end
2>.新建一个模型,作用是对cell里面的每一个控件设置frame 条件:
1>>.需要提供好一系列的CGRect类型的数据进行访问
2>>.提供一个接口来计算cell里面所有子控件的frame和cell的高度 如:- (void)setStatus:(Status *)status
//// StatusCellFrame.h// 微格//// Created by WHB on 14-7-22.// Copyright (c) 2014年 whblap. All rights reserved.//#define kCellBorderWidth 10#define kScreenNameFont [UIFont systemFontOfSize:17]#define kTimeFont [UIFont systemFontOfSize:13]#define kSourceFont kTimeFont#define kTextFont [UIFont systemFontOfSize:15]#define kRetweetedTextFont [UIFont systemFontOfSize:16]#define kRetweetedScreenNameFont [UIFont systemFontOfSize:16]#import <Foundation/Foundation.h>@class Status;@interface StatusCellFrame : NSObject// 一个StatusCellFrame对象 能 描述 一个StatusCell内部所有子控件的frame@property (nonatomic, strong) Status *status; // 根据status的内容来设置 各个属性的宽高 即提供的接口用来计算cell里面的所有控件的frame 和 cell@property (nonatomic, readonly) CGFloat cellHeight; // Cell的高度@property (nonatomic, readonly) CGRect iconFrame; // 头像的frame@property (nonatomic, readonly) CGRect screenNameFrame; // 昵称@property (nonatomic, readonly) CGRect timeFrame; // 时间@property (nonatomic, readonly) CGRect sourceFrame; // 来源@property (nonatomic, readonly) CGRect textFrame; // 内容@property (nonatomic, readonly) CGRect imageFrame; // 配图@property (nonatomic, readonly) CGRect retweetedFrame; // 被转发微博的父控件@property (nonatomic, readonly) CGRect retweetedScreenNameFrame; // 被转发微博作者的昵称@property (nonatomic, readonly) CGRect retweetedTextFrame; // 被转发微博的内容@property (nonatomic, readonly) CGRect retweetedImageFrame; // 被转发微博的配图@end
//// StatusCellFrame.m// 微格//// Created by WHB on 14-7-22.// Copyright (c) 2014年 whblap. All rights reserved.//#import "StatusCellFrame.h"#import "Status.h"#import "User.h"@implementation StatusCellFrame- (void)setStatus:(Status *)status{ _status = status; // 利用微博数据,计算所有子控件的frame // 整个cell的宽度 CGFloat cellWidth = [UIScreen mainScreen].bounds.size.width; // 1.头像 CGFloat iconX = kCellBorderWidth; CGFloat iconY = kCellBorderWidth; _iconFrame = CGRectMake(iconX, iconY, 50, 50); // 2.昵称 CGFloat screenNameX = CGRectGetMaxX(_iconFrame) + kCellBorderWidth; CGFloat screenNameY = iconY; CGSize screenNameSize = [status.user.screenName sizeWithFont:kScreenNameFont]; _screenNameFrame = (CGRect){{screenNameX, screenNameY}, screenNameSize}; // 3.时间 CGFloat timeX = screenNameX; CGFloat timeY = CGRectGetMaxY(_screenNameFrame) + kCellBorderWidth; CGSize timeSize = [status.createdAt sizeWithFont:kTimeFont]; _timeFrame = (CGRect){{timeX, timeY}, timeSize}; // 4.来源 CGFloat sourceX = CGRectGetMaxX(_timeFrame) + kCellBorderWidth; CGFloat sourceY = timeY; CGSize sourceSize = [status.source sizeWithFont:kSourceFont]; _sourceFrame = (CGRect) {{sourceX, sourceY}, sourceSize}; // 5.内容 CGFloat textX = iconX; CGFloat textY = CGRectGetMaxY(_sourceFrame) + kCellBorderWidth; CGSize textSize = [status.text sizeWithFont:kTextFont constrainedToSize:CGSizeMake(cellWidth - 2 * kCellBorderWidth, MAXFLOAT)]; _textFrame = (CGRect){{textX, textY}, textSize}; if (status.picUrls.count) { // 6.有配图 CGFloat imageX = textX; CGFloat imageY = CGRectGetMaxY(_textFrame) + kCellBorderWidth; _imageFrame = CGRectMake(imageX, imageY, 100, 100); } else if (status.retweetedStatus) { // 7.有转发的微博 // 被转发微博整体 CGFloat retweetX = textX; CGFloat retweetY = CGRectGetMaxY(_textFrame) + kCellBorderWidth; CGFloat retweetWidth = cellWidth - 2 * kCellBorderWidth; CGFloat retweetHeight = kCellBorderWidth; // 8.被转发微博的昵称 CGFloat retweetedScreenNameX = kCellBorderWidth; CGFloat retweetedScreenNameY = kCellBorderWidth; CGSize retweetedScreenNameSize = [status.retweetedStatus.user.screenName sizeWithFont:kRetweetedScreenNameFont]; _retweetedScreenNameFrame = (CGRect){{retweetedScreenNameX, retweetedScreenNameY}, retweetedScreenNameSize}; // 9.被转发微博的内容 CGFloat retweetedTextX = retweetedScreenNameX; CGFloat retweetedTextY = CGRectGetMaxY(_retweetedScreenNameFrame) + kCellBorderWidth; CGSize retweetedTextSize = [status.retweetedStatus.text sizeWithFont:kRetweetedTextFont constrainedToSize:CGSizeMake(retweetWidth - 2 * kCellBorderWidth, MAXFLOAT)]; _retweetedTextFrame = (CGRect){{retweetedTextX, retweetedTextY}, retweetedTextSize}; // 10.被转发微博的配图 if (status.retweetedStatus.picUrls.count) { CGFloat retweetedImageX = retweetedTextX; CGFloat retweetedImageY = CGRectGetMaxY(_retweetedTextFrame) + kCellBorderWidth; _retweetedImageFrame = CGRectMake(retweetedImageX, retweetedImageY, 100, 100); retweetHeight += CGRectGetMaxY(_retweetedImageFrame); } else { retweetHeight += CGRectGetMaxY(_retweetedTextFrame); } _retweetedFrame = CGRectMake(retweetX, retweetY, retweetWidth, retweetHeight); } // 11.整个cell的高度 _cellHeight = kCellBorderWidth; if (status.picUrls.count) { _cellHeight += CGRectGetMaxY(_imageFrame); } else if (status.retweetedStatus) { _cellHeight += CGRectGetMaxY(_retweetedFrame); } else { _cellHeight += CGRectGetMaxY(_textFrame); }}@end
3>.返回控制器,
在- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath方法中
1>>.创建一个自定义的Cell
2>>.实例化一个cellFrame
3>>.给Cell传递对应的cellframe;
在- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath方法中利用cellFrame
返回每一行cell的高度。
//// HomeViewController.m// 新浪微博控//// Created by whblap on 14-6-25.// Copyright (c) 2014年 whblap. All rights reserved.//#import "HomeViewController.h"#import "UIBarButtonItem+WHBALP.h"#import "HttpTool.h"#import "Status.h"#import "User.h"#import "StatusManage.h"#import "StatusCell.h"#import "StatusCellFrame.h"@interface HomeViewController (){ NSMutableArray *_statuses; // 所有的微博数据}@end@implementation HomeViewController- (void)viewDidLoad{ [super viewDidLoad]; [self buildNavigationBar]; [self loadStatusData];}#pragma mark - build导航栏- (void)buildNavigationBar{ self.title = @"首页"; self.view.backgroundColor = [UIColor cyanColor]; // 添加给导航栏左图片按钮 self.navigationItem.leftBarButtonItem = [UIBarButtonItem barButtonItemWithImage:@"navigationbar_compose.png" highlightedImage:@"navigationbar_compose_highlighted.png" addTarget:self action:@selector(sendStatus)]; // 给导航栏添加右图片按钮 self.navigationItem.rightBarButtonItem = [UIBarButtonItem barButtonItemWithImage:@"navigationbar_pop.png" highlightedImage:@"navigationbar_pop_highlighted.png" addTarget:self action:@selector(popMenu)];}#pragma mark - 加载微博数据- (void)loadStatusData{ _statuses = [NSMutableArray array];// [HttpTool getWithPath:@"2/statuses/home_timeline.json" params:nil success:^(id JSON) {// NSArray *statuses = JSON[@"statuses"]; // JSON返回的数据默认是20条 为数组类型的对象// // 将字典模型转化为模型对象(将模型对象添加到statuses微博数组中)// for (NSDictionary *dict in statuses) {// // // Status *status = [[Status alloc] initWithDict:dict];// [_statuses addObject:status];// }// NSLog(@"_____________%d",_statuses.count);// [self.tableView reloadData];// } failure:^(NSError *error) {// NSLog(@"%@",error);// }]; // 微博管理 加载 [StatusManage getStatusesWithSuccess:^(NSArray *statues) { [_statuses addObjectsFromArray:statues]; [self.tableView reloadData]; } failure:^(NSError *error) { NSLog(@"%@",error); }];}#pragma mark - 发送微博方法- (void)sendStatus{ MyLog(@"调用了发送微博方法"); }#pragma mark - 弹出菜单- (void)popMenu{ MyLog(@"调用了弹出菜单方法");}- (void)didReceiveMemoryWarning{ [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated.}#pragma mark - Table view data source- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ // Return the number of rows in the section. NSLog(@"++++++++++++++++%d",_statuses.count); return _statuses.count;}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *CellIdentifier = @"Cell"; StatusCell *cell = [tableView dequeueReusableCellWithIdentifier:nil]; if (cell == nil) { // 创建一个自定义的cell cell = [[StatusCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; } // 实例化一个微博frame对象 StatusCellFrame *sCellFrame = [[StatusCellFrame alloc] init]; // 将访问服务器得到的微博数据赋值给微博frame对象的status模型 需要根据这个设置frame sCellFrame.status = _statuses[indexPath.row]; [cell setStatusCellFrame:sCellFrame]; return cell;}#pragma mark 返回每一行cell的高度- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ StatusCellFrame *f = [[StatusCellFrame alloc] init]; f.status = _statuses[indexPath.row]; return f.cellHeight;}@end