zoukankan      html  css  js  c++  java
  • 05---MVC模式下动态调整Cell高度三部曲

    动态调整Cell高度三部曲

      我们在做项目开发的过程中经常会遇到每一个cell的高度及cell的子控件的显示个数不同,以我最近开发的微格为例,讲解一下MVC模式动态的调整Cell宽高的三部曲

      MVC模式一般都是 1.创建一个Model类 2.创建一个View类(View类含有Model属性) 3.在Controller类里面 实例化一个Model 实例化一个View 将实例化的Model赋值給View来显示数据。      

     

        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
  • 相关阅读:
    MFC的奇异non-modality模态对话框
    用于对话框,窗体视图,对话框和属性类型的布局管理器
    在。net中定制OpenFileDialog
    NFS的使用
    snmp-get
    zabbix-trap
    部署
    /etc/rc.local
    gj的交换机在升级了ios之后最新数据不刷新,
    计算型监控项
  • 原文地址:https://www.cnblogs.com/lszwhb/p/3865452.html
Copyright © 2011-2022 走看看