首页 > 代码库 > 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.h
////  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
StatusCell.m

    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.h
////  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
StatusCellFrame.m

    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
ViewController.m