现在的位置: 首页 > 综合 > 正文

iOS中Cell高度如何能够自动适应需要显示的内容

2013年07月12日 ⁄ 综合 ⁄ 共 15319字 ⁄ 字号 评论关闭


本文的代码例子 : "Cell行高自适应.zip" http://vdisk.weibo.com/s/Gb9Mt

在阅读本文之前要先学会JSON数据如何进行解析以及解析后的分类,如果对JSON解析不熟的话请先阅读下面这篇文章:http://blog.csdn.net/qqmcy/article/details/9196399在这篇文章中介绍了需要的知识。


下面我们来看看代码。我需要一个第三方库EGO异步下载、addtion文件夹和StringUtil文件以及Comment、Status、User这三个数据模型,这篇文章的主要目的是讲解如何计算Cell的高度,jSON数据分类见上面那篇文章,上面说的在代码例子中都有的。将它们考入你的工程。


实现思路:

/* 

  File.strings

  Cell行高自适应


  Created by on 13-4-2.

  Copyright (c) 2013. All rights reserved.

 

 实现类似微博这样的项目需要怎么做?

 1、首先,要获取数据。(这部分在网络请求中介绍)

 2、其次,将数据分类保存在对应的模型中。(这个技术在大字典中介绍)

 3、最后,将获取的数据显示在屏幕上。

 

 一、为什么要学习Cell的行高自适应?

 因为,我们要将获取的内容合理的显示在屏幕上。

 

 二、实现步骤

 1、要先将数据发送到显示界面的类ShowDataViewController

 2、计算获取每个数据单元需要在屏幕上占多大的空间,这个功能的实现在类Algorithm中,详细解释在类中。

 3、创建一个UITableViewCell类型的类:StatusCell这个类的作用就是为了设计如何在Cell中显示数据进行布局。

 

 三、技术难点:

 1、控件.autoresizingMask属性:每个控件几乎都有autoresizingMask的属性,该属性的作用是将改控件固定在相对的某个位置,例如:要将位置固定在当前cell的左下方,需要按下面的格式写UIViewAutoresizingFlexibleTopMargin代表是上方、UIViewAutoresizingFlexibleRightMargin是右方的意思。因此写代码设置控件的相对位置需要写出相反的方向。 


*/



我们先实现一个计算Cell高度的类:

Algorithm.h

#import <Foundation/Foundation.h>
#import "Status.h"
@interface Algorithm : NSObject

-(CGFloat)cellHeight:(NSString*)contentText with:(CGFloat)with;
//计算Cell的高度 
-(CGFloat)calculation:(NSIndexPath*)indexPath StatusArr:(NSMutableArray*)statusArr;


@end

Algorithm.m

#import "Algorithm.h"
#define kTextViewPadding            16.0
#define kLineBreakMode1              UILineBreakModeWordWrap
@implementation Algorithm
-(CGFloat)calculation:(NSIndexPath *)indexPath StatusArr:(NSMutableArray *)statusArr
{
    NSInteger row = indexPath.row;
    if (row >= [statusArr count]) {
        return 1;
    }
    Status* status = [statusArr objectAtIndex:row];

    NSString* url = status.retweetedStatus.thumbnailPic;
    
    NSString* url2 = status.thumbnailPic;
 
    CGFloat height  = 0.0f;
    
    if (status.retweetedStatus && ![status.retweetedStatus isEqual:[NSNull null]]) {
        //调用下面-(CGFloat)cellHeight:(NSString *)contentText with:(CGFloat)with的方法计算一段文字所占的高度
        height = [self cellHeight:status.text with:320.0f] + [self cellHeight:[NSString stringWithFormat:@"%@:%@",status.retweetedStatus.user.screenName,status.retweetedStatus.text] with:300.0f] - 22.0f;
        NSLog(@"status.retweetedStatus,height = %f",height);
    }
    else
    {
        height = [self cellHeight:status.text with:320.0f];
        //后加调式用
        height+=40;
        NSLog(@"height = %f",height);
    }
    if ((url && [url length] != 0) || (url2 && [url2 length] != 0)) {
        //如果有图片将高度增加80个像素
        height = height + 80;
        NSLog(@"height = %f",height);
    }
    return height;
    
}


//计算一段文字的高度
-(CGFloat)cellHeight:(NSString *)contentText with:(CGFloat)with
{
    
    UIFont* font = [UIFont systemFontOfSize:14];
   //sizeWithFont:字体大小constrainedToSize:显示的范围lineBreakMode:
    CGSize size = [contentText sizeWithFont:font constrainedToSize:CGSizeMake(with - kTextViewPadding , 3000000.f) lineBreakMode:kLineBreakMode1];
    CGFloat height = size.height + 44;
    return height;
}

接下来我们创建一个继承自UITableViewCell

StatusCell.h

#import <UIKit/UIKit.h>
#import "Status.h"
#import "EGOImageView.h"
@interface StatusCell : UITableViewCell

@property (nonatomic, retain) UITableViewCell* tableViewCell;
@property (nonatomic, retain) UITableView*     tableVw;
@property (nonatomic, retain) NSMutableArray* StatusArr;

@property (retain, nonatomic)  UILabel *countLB;             //数量
@property (retain, nonatomic)  EGOImageView *avatarImage;
@property (retain, nonatomic)  UITextView *contentTF;        //微博正文
@property (retain, nonatomic) UILabel *userNameLB;
@property (retain, nonatomic)  UIImageView *bgImage;         //微博背景
@property (retain, nonatomic)  EGOImageView *contentImage;  //正文的图片
@property (retain, nonatomic)  UIView *retwitterMainV;       //转发的View
@property (retain, nonatomic)  EGOImageView *retwitterBgImage;     //转发的背景
@property (retain, nonatomic)  UITextView *retwitterContentTF;//转发的正文
@property (retain, nonatomic)  EGOImageView *retwitterContentImage;//转发正文的图片
//@property (assign, nonatomic) id<StatusViewCellDelegate> delegate;
@property (retain, nonatomic) NSIndexPath *cellIndexPath;
@property (retain, nonatomic)  UILabel *fromLB;
@property (retain, nonatomic)  UILabel *timeLB;
@property (retain, nonatomic)  UILabel* sourceLB;  //微博来源


-(CGFloat)setTFHeightWithImage:(BOOL)hasImage haveRetwitterImage:(BOOL)haveRetwitterImage;
-(void)setupCell:(Status*)status;

-(void)controlPosition;

@end


StatusCell.m

本文中CELL中的控件全部用代码实现,所以下面的代码比较多。

#define IMAGE_VIEW_HEIGHT 80.0f
#import "StatusCell.h"

@implementation StatusCell

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
 
        // Initialization code
        //点击Cell时背景不变蓝
        self.selectionStyle = UITableViewCellSelectionStyleNone;
        
        self.bgImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"table_header_bg.png"]];
        self.bgImage.frame = CGRectMake(0, 29 , 320, 73);
       // self.bgImage.contentMode = UIViewContentModeScaleToFill;
        [self.contentView addSubview:self.bgImage];
        
        
        self.avatarImage = [[EGOImageView alloc] initWithFrame: CGRectMake(5.0 , 5.0, 22, 22)];
        
        self.avatarImage.image = [UIImage imageNamed:@"loadingImage_50x118.png"];
        self.avatarImage.contentMode = UIViewContentModeScaleToFill;
        [self.contentView addSubview:self.avatarImage];
                            
        
        self.userNameLB = [[UILabel alloc] initWithFrame:CGRectMake(35, 0, 165, 28)];
        self.userNameLB.font = [UIFont systemFontOfSize:17.0];
        self.userNameLB.backgroundColor = [UIColor clearColor];
        [self.contentView addSubview:self.userNameLB];
        
        self.contentTF = [[UITextView alloc] init];
        self.contentTF.editable = NO;
        self.contentTF.frame = CGRectMake(0, 29 , 320, 73);
        self.contentTF.font = [UIFont systemFontOfSize:14.0];
        //UITextView如果有网址可以直接打开
        self.contentTF.dataDetectorTypes = UIDataDetectorTypeLink;
        //开启多点触摸
        self.contentTF.multipleTouchEnabled = YES;
        self.contentTF.backgroundColor = [UIColor clearColor];
        [self.contentView addSubview:self.contentTF];
        
        
        self.contentImage = [[EGOImageView alloc] initWithImage:[UIImage imageNamed:@"loadingImage_50x118.png"]];
        self.contentImage.frame = CGRectMake(90, 84, 140, 80);
        self.contentImage.backgroundColor = [UIColor clearColor];
        [self.contentView addSubview:self.contentImage];
        
        
        
        
        self.retwitterMainV = [[UIView alloc] initWithFrame:CGRectMake(0, 166, 320, 160)];
        self.retwitterMainV.contentMode = UIViewContentModeScaleAspectFill;
        self.retwitterMainV.backgroundColor = [UIColor clearColor];
        [self.contentView addSubview:self.retwitterMainV];
        
        //转发背景图
        self.retwitterBgImage = [[EGOImageView alloc] initWithFrame:CGRectMake(-10, -10, 320, 100)];
        self.retwitterBgImage.contentMode = UIViewContentModeScaleToFill;
        self.retwitterBgImage.backgroundColor = [UIColor clearColor];
        [self.retwitterMainV addSubview:self.retwitterBgImage];
        
        //转发的正文
        self.retwitterContentTF = [[UITextView alloc] initWithFrame:CGRectMake(10, 5, 300, 150)];
        self.retwitterContentTF.editable = NO;
        self.retwitterContentTF.backgroundColor = [UIColor clearColor];
        [self.retwitterMainV addSubview:self.retwitterContentTF];
        
        //转发的图片
        self.retwitterContentImage = [[EGOImageView alloc] initWithFrame:CGRectMake(90, 100, 140, 80)];
        self.retwitterContentImage.backgroundColor = [UIColor clearColor];
        self.retwitterContentImage.contentMode = UIViewContentModeScaleAspectFit;
        [self.retwitterMainV addSubview:self.retwitterContentImage];
        
        
        self.countLB = [[UILabel alloc] init];
        self.countLB.backgroundColor = [UIColor clearColor];
        [self.countLB setFont:[UIFont fontWithName:@"Arial Rounded MT Bold" size:13.0]];
        self.countLB.autoresizingMask = UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleLeftMargin;
        [self.contentView addSubview:self.countLB];
        
        self.sourceLB = [[UILabel alloc] init];
        self.sourceLB.backgroundColor = [UIColor clearColor];
        [self.sourceLB setFont:[UIFont fontWithName:@"Arial Rounded MT Bold" size:13.0]];
        //每个控件几乎都有autoresizingMask的属性,该属性的作用是将改控件固定在相对的某个位置,例如:要将位置固定在当前cell的左下方,需要按下面的格式写UIViewAutoresizingFlexibleTopMargin代表是上方、UIViewAutoresizingFlexibleRightMargin是右方的意思。因此写代码设置控件的相对位置需要写出相反的方向。  
        self.sourceLB.autoresizingMask = UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleRightMargin;
        [self.contentView addSubview:self.sourceLB];
        
        self.timeLB = [[UILabel alloc] initWithFrame:CGRectMake(200, 0, 165, 28)];
        [self.timeLB setFont:[UIFont fontWithName:@"Arial Rounded MT Bold" size:13.0]];
        self.timeLB.backgroundColor = [UIColor clearColor];
        [self.contentView addSubview:self.timeLB];
        
      
    }
    return self;
}


-(void)setupCell:(Status *)status
{
    //头像图片的网址
    NSURL* avatarImageUrl = [NSURL URLWithString:status.user.profileImageUrl];
    //正文图片的网址
    NSURL* contentImageUrl = [NSURL URLWithString:status.thumbnailPic];
    //转发图片的方法
    NSURL* retweetedStatusUrl = [NSURL URLWithString:status.retweetedStatus.thumbnailPic];
    
    self.contentTF.text = status.text;
    self.userNameLB.text = status.user.screenName;
    self.timeLB.text = [status timestamp];
    self.avatarImage.imageURL =avatarImageUrl;
    
    self.countLB.text = [NSString stringWithFormat:@"评论:%d 转发:%d",status.commentsCount,status.retweetsCount];
    self.fromLB.text = [NSString stringWithFormat:@"来自:%@",status.source];
    self.timeLB.text = status.timestamp;
    
    self.sourceLB.text = [NSString stringWithFormat:@"来源:%@",status.source];
    Status  *retwitterStatus    = status.retweetedStatus;
    
    //有转发
    if (retwitterStatus && ![retwitterStatus isEqual:[NSNull null]])
    {
        self.retwitterMainV.hidden = NO;
        self.retwitterContentTF.text = [NSString stringWithFormat:@"%@:%@",status.retweetedStatus.user.screenName,retwitterStatus.text];
        self.contentImage.hidden = YES;
        
        if (![retweetedStatusUrl isEqual:[NSNull null]])
        {
            self.retwitterContentImage.imageURL = retweetedStatusUrl;
        }
        
        NSString *url = status.retweetedStatus.thumbnailPic;
        self.retwitterContentImage.hidden = url != nil && [url length] != 0 ? NO : YES;
        [self setTFHeightWithImage:NO
                haveRetwitterImage:url != nil && [url length] != 0 ? YES : NO];//计算cell的高度,以及背景图的处理
    }
    
    //无转发
    else
    {
        self.retwitterMainV.hidden = YES;
        if (![contentImageUrl isEqual:[NSNull null]]) {
            self.contentImage.imageURL = contentImageUrl;
        }
        
        NSString *url = status.thumbnailPic;
        self.contentImage.hidden = url != nil && [url length] != 0 ? NO : YES;
        [self setTFHeightWithImage:url != nil && [url length] != 0 ? YES : NO
                haveRetwitterImage:NO];//计算cell的高度,以及背景图的处理
    }
}


//计算cell的高度,以及背景图的处理
-(CGFloat)setTFHeightWithImage:(BOOL)hasImage haveRetwitterImage:(BOOL)haveRetwitterImage
{
    [self.contentTF layoutIfNeeded];
    
    //博文Text
    CGRect frame = self.contentTF.frame;
    frame.size = self.contentTF.contentSize;
    self.contentTF.frame = frame;
    //设置正文的背景
    self.bgImage.frame = frame;
    
    //转发博文Text
    frame = self.retwitterContentTF.frame;
    frame.size = self.retwitterContentTF.contentSize;
    self.retwitterContentTF.frame = frame;
    //调整转发背景
    self.retwitterBgImage.image = [[UIImage imageNamed:@"timeline_rt_border_t.png"] stretchableImageWithLeftCapWidth:130 topCapHeight:7];
    frame.origin.x -=10;
    frame.origin.y -=5;
    frame.size.width = frame.size.width +15;
    
    self.retwitterBgImage.frame = frame;
    
    //转发的主View
    frame = self.retwitterMainV.frame;
    
    if (haveRetwitterImage) frame.size.height = self.retwitterContentTF.frame.size.height + IMAGE_VIEW_HEIGHT + 15;
    else frame.size.height = self.retwitterContentTF.frame.size.height + 15;
    
    if(hasImage) frame.origin.y = self.contentTF.frame.size.height + self.contentTF.frame.origin.y + IMAGE_VIEW_HEIGHT;
    else frame.origin.y = self.contentTF.frame.size.height + self.contentTF.frame.origin.y;
    
    self.retwitterMainV.frame = frame;
    
    
    //转发的图片
    frame = self.retwitterContentImage.frame;
    frame.origin.y = self.retwitterContentTF.frame.size.height;
    frame.size.height = IMAGE_VIEW_HEIGHT;
    self.retwitterContentImage.frame = frame;
  
    //正文的图片
    frame = self.contentImage.frame;
    frame.origin.y = self.contentTF.frame.size.height + self.contentTF.frame.origin.y - 5.0f;
    frame.size.height = IMAGE_VIEW_HEIGHT;
    self.contentImage.frame = frame;
   
    //背景设置
    self.bgImage.image = [[UIImage imageNamed:@"table_header_bg.png"] stretchableImageWithLeftCapWidth:10 topCapHeight:10];
    
  //   = self.retwitterContentTF.frame;
    return self.contentTF.contentSize.height;
}


-(void)controlPosition
{
      self.countLB.frame = CGRectMake(198, self.frame.size.height - 20, 142, 21);
    self.sourceLB.frame = CGRectMake(20, self.frame.size.height - 20, 152, 21);
 
}

再创建一个继承自的UIViewController类ShowDataViewController这个类用来创建tableView以及显示Cell中的内容。

ShowDataViewController.h


#import <UIKit/UIKit.h>
#import "Algorithm.h"
@interface ShowDataViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>
//创建一个UITableView
@property (strong, nonatomic) UITableView* tb;
//Algorithm类的作用是根据内容计算Cell的高度
@property (strong, nonatomic) Algorithm* algorithm;
//用一个NSMutableArray接收Status类的对象
@property (strong , nonatomic) NSMutableArray* statusArr;
@end


ShowDataViewController.m


-(id)init
{
    if (self = [super init]) {
        //为什么要在init方法中注册消息中心,这样可以在AppDelegate方法中初始化这个类时注册消息中心
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getArray:) name:@"getArray" object:nil];
    }
    return self;
}


-(void)getArray:(NSNotification*)aNotification
{
    //接收传过来的数组,数组中存有Status类的对象
    self.statusArr = aNotification.object;
}


- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view.
    self.tb = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 548) style:UITableViewStylePlain];
    self.tb.delegate = self;
    self.tb.dataSource = self;
    [self.view addSubview:self.tb];
    self.algorithm = [[Algorithm alloc] init];
    
    
   
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [self.statusArr count];
}


-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    //调用Algorithm类的方法计算cell的高度 这个方法如何实现见Algorithm类中的注释
    CGFloat height = [self.algorithm calculation:indexPath StatusArr:self.statusArr];
    
    return height;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    int  row = indexPath.row;
   static NSString* strIdentifier = @"StatusCell";
//    
//    //自定义Cell只需要将初始化的类变成自定义的Cell
    StatusCell* cell  = [tableView dequeueReusableCellWithIdentifier:strIdentifier];
    if (cell == nil)
    {
        cell =  [[StatusCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:strIdentifier];
    }
    //下面这个方法是用来调整控件坐标的
    [cell controlPosition];
    //Status是储存微博信息的类,将数组中的微博类的对象按照行号取出
    Status* status = [self.statusArr objectAtIndex:row];
    NSLog(@"row = %d",row);
    //下面这个方法是将微博信息放在Cell中
    [cell setupCell:status];

    
    return cell;
    
}

接下来我们在ViewController类中添加如下代码

ViewController.h


@interface ViewController : UIViewController
-(IBAction)changeVC:(id)sender;
-(IBAction)sendData:(id)sender;
@end


自己在XIB中拖2个button与下面两个方法相关联吧

-(IBAction)sendData:(id)sender
{
    //将JSON格式的数据文件的路径找出
    NSString* path = [[NSBundle mainBundle] pathForResource:@"jsonTest" ofType:@"json"];
    //将数据放入NSData中
    NSData* data = [NSData dataWithContentsOfFile:path];
    //JSON解析
    NSDictionary* dic =  [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
    //    NSLog(@"dic = %@",dic);
    
    
    
    
    
    NSArray* arr = [dic objectForKey:@"statuses"];
    NSLog(@"%d",arr.count);
    NSLog(@"arr = %@",arr);
    
    
    //初始化一个数组
    NSMutableArray* tempArr = [NSMutableArray array];
    //将数组中的字典放入Status模型中,大家在这里会有一个疑问将数组中的字典都放入模型中,怎么区分不同数组中的数据?
    for (NSDictionary* item in arr) {
        //答案在statusWithJsonDictionary:的类方法中见该方法注释
        Status* status = [Status statusWithJsonDictionary:item];
        
        
        
        
        //将Status类型的对象放入数组中
        [tempArr addObject:status];
    }
    //将tempArr数组通过消息中心发送到@"getArray" 这个名字的消息对应的方法中
    [[NSNotificationCenter defaultCenter] postNotificationName:@"getArray" object:tempArr];
}

-(IBAction)changeVC:(id)sender
{
    //切换视图控制器
    [[NSNotificationCenter defaultCenter] postNotificationName:@"changeVC" object:nil];

}

我们还要在AppDelegate类中添加如下代码。

#import <UIKit/UIKit.h>
#import "ShowDataViewController.h"
@class ViewController;

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@property (strong, nonatomic) ViewController *viewController;
@property (strong, nonatomic) ShowDataViewController* showVC;

@end


AppDelegate.m

#import "AppDelegate.h"
#import "ShowDataViewController.h"
#import "ViewController.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
	//为了注册消息
    [[ShowDataViewController alloc] init];
//注册消息为了切换视图控制器
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeVC) name:@"changeVC" object:nil];
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
    self.showVC = [[ShowDataViewController alloc] init];
    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];
    return YES;
}

-(void)changeVC
{
    self.window.rootViewController = self.showVC;
}




抱歉!评论已关闭.