如何在UITableViewCell中重新定位子视图?

时间:2009-07-03 08:37:26

标签: iphone uitableview

我正在编写一个从网上检索一些信息的线程UITableView。我希望在图像加载时显示一个活动指示符来代替常规的cell.image。

问题是自定义标签和活动指示器的行为不正常。标签从正确的位置开始,活动指示器显示在正确的位置并开始动画,但是一旦在图像下载线程上点击第一个回调(基本上只加载了一个图像),所有视图重置好像有一个引用,我正在重置所有这些帧...

我有重载 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

有问题的代码在这里:

// Set up the cell...
    if( ![[cell contentView] viewWithTag:indexPath.row+200] ){
        UILabel *newLabel = [[UILabel alloc] init];
        newLabel.text = [[personList objectAtIndex:indexPath.row] name];
        newLabel.frame = [[cell contentView] frame];
        [[cell contentView] addSubview:newLabel];
        newLabel.tag = indexPath.row+200;
        [newLabel release];
    }
    else{
        UILabel *alreadySetLabel = (UILabel *)[[cell contentView] viewWithTag:indexPath.row+200];
        alreadySetLabel.text = [[personList objectAtIndex:indexPath.row] name];
        alreadySetLabel.frame = [[cell contentView] frame];
    }

    UIImageView *tmpImageView = cell.imageView;

    NSLog( @"In cell name: %@", [[personList objectAtIndex:indexPath.row] name] );
    NSLog( @"In cell profile image: %@", [[personList objectAtIndex:indexPath.row] profileImage] );

    if( [[personList objectAtIndex:indexPath.row] profileImage] ){
        tmpImageView.image = [[personList objectAtIndex:indexPath.row] profileImage];
        [[[cell contentView] viewWithTag:indexPath.row+100] removeFromSuperview];
        UILabel *labelRef1 = (UILabel *)[[cell contentView] viewWithTag:indexPath.row+200];
        [labelRef1 setFrame:CGRectMake( cell.contentView.frame.origin.x+70, cell.contentView.frame.origin.y, labelRef1.frame.size.width, labelRef1.frame.size.height)];
    }
    else{
        NSLog( @"%@", [[personList objectAtIndex:indexPath.row] imageFilePath] );
        if( ![[cell contentView] viewWithTag:indexPath.row+100] && [[personList objectAtIndex:indexPath.row] imageFilePath] ){
            UIActivityIndicatorView *newSpin = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
            [newSpin setTag:indexPath.row+100];
            [newSpin startAnimating];
            [newSpin setFrame:CGRectMake( 5, ((cell.contentView.frame.size.height/2)-7), 30, ((cell.contentView.frame.size.height/2)-7)+15) ];
            [[cell contentView] addSubview:newSpin];
            [newSpin release];
            UILabel *labelRef2 = (UILabel *)[cell viewWithTag:indexPath.row+200];
            [labelRef2 setFrame:CGRectMake( cell.contentView.frame.origin.x+70, cell.contentView.frame.origin.y, labelRef2.frame.size.width, labelRef2.frame.size.height)];
        }
    }

全新的iphone应用程序开发,不到两周。我想知道我是否误解了标签的使用?在我看来,如果你可以将标记值链接到indexPath,你可以提出唯一标识符来引用自定义视图吗? 100和200是任意值,这样我就不会在一个屏幕数据中意外地重复使用这些标签 - 不知道是否有必要,因为我认为标签只能通过子视图进行搜索。

提前感谢任何建议。还有一些关于如何使这更优雅的一般提示......

谢谢, 约什

2 个答案:

答案 0 :(得分:1)

我不确定你的意思究竟是什么意思“所有重置的视图好像只有一个参考,我正在重置所有这些的框架”,但让我指出一些事情。一般情况下使用标签和加载表格查看单元格图像。

标记只是在一个视图中识别/检索子视图的一种方式 - 它们不必是全局唯一的。实际上,在标记值中加入indexPath.row根本不是一个好主意,因为表视图单元格重用(只要你使用dequeueReusableCellWithIdentifier:,你肯定应该这样做)。此外,我会将标记值定义为常量(例如#define),并仅在代码中引用这些常量。这样,您的代码就更具描述性,更不容易出错并且更易于维护。

说实话,我根本不喜欢使用标签。实际上,在tableView:cellForRowAtIndexPath:中“动态”构建表格视图单元格是我遇到的唯一没有其他选择的场景(因为您没有任何命名的出口)。我建议你继承UITableViewCell而不是搞乱标签。这真的没什么大不了的,但是你的代码会更清晰,你可以轻松地封装该类中所有与单元格相关的东西 - 当你做更复杂的事情,比如在网络上异步加载表格视图单元格时,这一点尤为重要。“ p>

关于异步图片加载的内容,你看过this project on github了吗?它基本上是一个演示项目,用于演示如何异步加载(flickr)图像并在完成加载时在表视图中更新它们 - 这不是一个完美的实现,但至少是一个很好的起点。我最近做了同样的事情,但我的方法是子类UIImageView并在此子类中执行所有异步加载/更新。主要原因是我想要一个通用且可重复使用的解决方案。

答案 1 :(得分:0)

你是对的 - 对单元进行子类化将是封装和代码量的方法。我必须改变它。

另一方面,我用一个额外的代码分支解决了这个问题。

为了澄清,问题是我添加到子视图的自定义标签每次表重新加载数据时都会重置其帧。您会注意到我将其移动超过70像素,以便为活动指示器或已加载的图像腾出空间。它会在第一次执行此操作,然后每次在后台线程上加载其他图片时重置为origin.x = 0.

显然,标签框架无论如何都会重置?我的代码将检测单元格contentView中的子视图,其标记为100(我按照你的建议将其更改为静态值,并且之前没有),并且什么都不做,因为我认为rect会保持静态因为观点存在。事实并非如此,无论是否存在,我都必须明确设置框架。无论如何,可能只是我不明白最新情况。只要我在其他地方添加了一个额外的setFrame,一切正常。

谢谢, 约什