ios - 尝试理解在处理UITableViewCells时cellForRowAtIndexPath和heightForRowAtIndexPath的工作原理

时间:2012-08-07 19:45:29

标签: ios ios5 uitableview

在StackOverflow的优秀人员的帮助下,我有两种方法:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{    
    UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:(UITableViewCellStyleDefault)
            reuseIdentifier:@"business"];

    NSString *comment = [[items_array objectAtIndex:[indexPath row]] objectForKey:(@"comment")];

    NSLog(businessPrivacy);
    // FIND IF THE BUSINESS PLAN IS PRIVATE OR NOT.

        CGSize constraint = CGSizeMake(320 - (10 * 2), 20000.0f); 

        CGSize size = [comment sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap]; 

        UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 300, MAX(size.height, 44.0f) + 20.0f)]; 
        label.numberOfLines = 0; 
        label.lineBreakMode = UILineBreakModeWordWrap; 
        label.text = comment;  

        [cell.contentView addSubview:label];        

    return cell;
}

//Cell size for word wrapping.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{    
    NSString *comment = [[items_array objectAtIndex:[indexPath row]] objectForKey:(@"comment")];

    CGSize constraint = CGSizeMake(320 - (10 * 2), 20000.0f); 

    CGSize size = [comment sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap]; 

    CGFloat height = MAX(size.height, 44.0f);

    return height + (10 * 2);
}

它们具有的效果是将字体大小从默认字体大小减小,并且动态调整大小到ALMOST,无论文本可能有多长,都适合注释的整个文本。

我感到困惑的是,我在这两种方法中都有一些相同的代码,我不知道它应该是什么样子。我知道这两种方法都被调用了,但不确定应该在哪里,以便它们正常工作。

提前感谢您的建议。

3 个答案:

答案 0 :(得分:3)

看起来你需要它们。我已经用注释重写了你的代码,以便你能理解它:

//This function is used to create the cell and the content of the cell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{   
    //Here you are allocating a new cell with a reuse identifier.  This is only needed if
    //you plan on reusing the cells and using [tableView dequeueReusableCellWithIdentifier:cellIdentifier]
    //Reusable cells will save you some memory and make your tableview work more smoothly,
    //however here you are not selecting from the reusable pool, and are instead making a new cell each time
    UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:(UITableViewCellStyleDefault)
            reuseIdentifier:@"business"];

    //This is pulling the text for the comment, it is obviously necessary
    NSString *comment = [[items_array objectAtIndex:[indexPath row]] objectForKey:(@"comment")];

    NSLog(businessPrivacy);
    // FIND IF THE BUSINESS PLAN IS PRIVATE OR NOT.

    // This is creating a constraint size for the label you are making
    CGSize constraint = CGSizeMake(320 - (10 * 2), 20000.0f); 

    // This is determining the size that you will need for the label based on the comment
    // length and the contraint size
    CGSize size = [comment sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap]; 

    //  Here you are creating your label and initializing it with the frame that you have
    //  determined by your size calculations above
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 300, MAX(size.height, 44.0f) + 20.0f)];

    // setting up the label properties
    label.numberOfLines = 0;
    label.lineBreakMode = UILineBreakModeWordWrap; 
    label.text = comment;  

    // adding the label view to the cell that you have created
    [cell.contentView addSubview:label];        

    // return the cell for the table view
    return cell;
}

//Cell size for word wrapping.
//This method will determine how tall each row needs to be.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
    //Here you are getting the comment again.  This is necessary to determine how tall you need
    //the cell to be    
    NSString *comment = [[items_array objectAtIndex:[indexPath row]] objectForKey:(@"comment")];

    // Again you are getting the constraints because you are going to us this size
    // to constrain the height of the cell just like you determined the size for the label.
    CGSize constraint = CGSizeMake(320 - (10 * 2), 20000.0f); 

    // Again, determining the size that we will need for the label, because it will drive
    // the height of the cell
    CGSize size = [comment sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap]; 

    //  Finally, we can determine the height for the cell!
    CGFloat height = MAX(size.height, 44.0f);

    //  return the height, which is the height of the label plus some extra space to make
    //  it look good.
    return height + (10 * 2);
}

基本上,cellForRow...函数创建单元格的内容,heightForRow...函数确定高度。您需要所有这些信息,因为cell函数只创建单元格的内容,而height函数创建行的高度,注释,约束和大小都很重要确定单元格内容的label大小和单元格的高度。

答案 1 :(得分:1)

所以heightForRowAtIndexPath,顾名思义,只处理细胞的高度。即该函数的返回值(CGFloat)是指定索引路径上单元格的高度。

另一方面,

cellForRowAtIndexPath设置实际单元格,包括其所有子视图。会发生什么,比如一些单元格有一个5行UILabel,有些单元格有1行。然后,您需要在heightForRowAtIndexPath中调整单元格的大小,但同时您还需要在UILabel中调整单元格内cellForRowAtIndexPath的大小。后者不会自动发生。你需要自己照顾。

答案 2 :(得分:1)

如果必须两次或多次编写相同的代码,则应考虑将重复的代码提取到方法或函数中。但是你还有一些我们应该解决的问题。

让我们声明一些常量,这样我们就不必在整个代码中重复数字了:

static const CGFloat kLabelMargin = 10.0f;
static const CGFloat kLabelWidth = 320.0f - 2.0f * kLabelMargin;

您在两种方法中重复的一行都会查找一行的注释。让我们来做一个方法:

- (NSString *)commentForRowAtIndexPath:(NSIndexPath *)indexPath {
    return [[items_array objectAtIndex:[indexPath row]] objectForKey:@"comment"];
}

其他重复的代码计算行的高度,所以让我们创建一个函数来返回:

static CGFloat heightForComment(NSString *comment) {
    CGSize constraint = CGSizeMake(kLabelWidth, 20000.0f);
    CGSize size = [comment sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
    return MAX(size.height, 44.0f) + 2.0f * kLabelMargin;
}

现在我们可以重写您的tableView:heightForRowAtIndexPath:方法:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return heightForComment([self commentForRowAtIndexPath:indexPath]);
}

最后,让我们重写您的tableView:cellForRowAtIndexPath:方法。我们将使其适当地重用单元格(以避免浪费内存),并且我们将使用我们创建的新方法和函数。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *const kReuseIdentifier = @"business";
    static const NSInteger kLabelTag = 1;

    NSLog(@"%@", businessPrivacy);
    // FIND IF THE BUSINESS PLAN IS PRIVATE OR NOT.

    NSString *comment = [self commentForRowAtIndexPath:indexPath];
    CGRect labelFrame = CGRectMake(0, 0, kLabelWidth, heightForComment(comment));

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kReuseIdentifier];
    UILabel *label;
    if (cell) {
        label = (UILabel *)[cell.contentView viewWithTag:kLabelTag];
        label.frame = labelFrame;
    } else {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kReuseIdentifier];
        label = [[UILabel alloc] initWithFrame:labelFrame];
        label.tag = kLabelTag;
        label.numberOfLines = 0;
        label.lineBreakMode = UILineBreakModeWordWrap;
        [cell.contentView addSubview:label];
    }

    label.text = comment;

    return cell;
}