【问题标题】:Check if UIButton already exists on UITableViewCell检查 UITableViewCell 上是否已经存在 UIButton
【发布时间】:2013-02-07 13:11:45
【问题描述】:

对于每个UITableViewCell,我在tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath 方法中创建一个UIButton。我想在创建它时检查UIButton是否已经存在,所以它没有被多次添加,但我不能。这是我的代码:

- (UITableViewCell *)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {

        UIImageView *cellBottomLine = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, CELL_HEIGHT, 320.0, 1)];
        cellBottomLine.image = [UIImage imageNamed:@"bottomCellImage.png"];
    if (cellBottomLine.subviews) {
        [cell addSubview:cellBottomLine];
    }

        copyButton = [BSFunctions createButtonWithNormalImageNamed:@"copyCellButton.png" highlightedImageName:@"copyCellButtonPressed.png" target:self selector:@selector(copyPressedFromCell:)];
        [copyButton setFrame:CGRectMake(250, 10, 62, 32.5)];
        copyButton.tag = indexPath.row;
    if (!copyButton.superview) {
        [cell addSubview:copyButton];
    }

    return cell;
}

【问题讨论】:

  • 为什么不在cellForRowAtIndexPath:方法中添加按钮?
  • 我会接受 Kuba 的建议,您可以在检查单元格是否不为零的同时添加按钮,这样也不会产生冗余。

标签: iphone ios objective-c cocoa-touch uitableview


【解决方案1】:
- (UITableViewCell *)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
     UIImageView *cellBottomLine = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, CELL_HEIGHT, 320.0, 1)];
cellBottomLine.image = [UIImage imageNamed:@"bottomCellImage.png"];
    if (cellBottomLine.subviews) 
    {
        [cell addSubview:cellBottomLine];
    }

    for (UIView *view in [cell subviews]) 
    {
        if ([view isKindOfClass:[UIButton class]]) 
        {
             return cell;
        }
    }

    copyButton = [BSFunctions createButtonWithNormalImageNamed:@"copyCellButton.png"
                                          highlightedImageName:@"copyCellButtonPressed.png"
                                                        target:self
                                                      selector:@selector(copyPressedFromCell:)];
    [copyButton setFrame:CGRectMake(250, 10, 62, 32.5)];
    copyButton.tag = indexPath.row;
    if (!copyButton.superview)
    {
        [cell addSubview:copyButton];
    }

    return cell;
}

【讨论】:

  • 您的答案确实有效,但奇怪的是,每次当单元格移出 UITableView 的大小时,它都会在 cell.subviews 处添加 1 个子视图。关于它可能是什么的任何想法?
  • 它可能是您正在添加的“cellBottomLine”图像视图,每次调用该函数时都会添加它。按照您的要求,我专门为 UIButton 视图编写了代码。但是,如果也不想添加 imageView(如果它已经存在),请告诉我。我将编辑我的答案。
【解决方案2】:

我认为您应该使用cellForRowAtIndexPath 方法将任何子视图添加到单元格,以便在来回滚动时重复使用单元格,并且在将子视图添加到单元格之前不需要进行任何检查。

【讨论】:

  • 很遗憾,当使用您提出的方法时,当 UITableView 滚动出视图的内容时,UIButtons 的状态会重置。
  • 那么你的 cellForRowAtIndexPath 方法中应该有一些错误。您是否在该方法中使用了可重用标识符?
  • 为了解决重置按钮问题,我认为通常的技术是在viewDidLoad(或viewDidLoad调用的自定义子程序)中构建一个单元格数组,然后使用cellForRowAtIndexPath显示数组中该索引处的单元格。据我了解,即使该单元格不在屏幕上,将单元格放入数组中也会使它们保持不变,因此当重新显示单元格时,不会重新创建(并因此重置)UIControls。
【解决方案3】:

Stavash 的答案是最好的,但如果您不想这样做,也可以使用tableView:cellForRowAtIndexPath:。我看到您尝试过,并且在滚动时按钮的状态丢失了。我认为这是由于细胞重用。通过单元格重用,一旦表格视图单元格离开屏幕,它就会被缓存并带有标识符,然后屏幕上的下一个单元格会从缓存中检索具有给定标识符的单元格。

为避免按钮在离开屏幕时丢失其状态,您可以使用多个重用标识符并将按钮的状态存储在一个数组中。我们将此属性称为buttonStates(它应该是一个可变数组)。

初始化您的 buttonStates 变量并添加字符串来表示“基本状态”。添加与表格中单元格数量一样多的这些字符串(我假设根据您的代码只有一个部分)。

当状态改变时(这可能发生在你的copyPressedFromCell: 方法中,用一个代表新状态的字符串更新按钮标签索引处的对象(你已经设置为单元格的索引)。

完成所有这些后,让您的 cellForRowAtIndexPath: 方法如下所示:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *CellIdentifier = self.buttonStates[indexPath.row];
    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (!cell) {
        cell = [UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];

在我们继续之前,让我们看一下您的一些willDisplayCell: 代码(应该移到这里)。

UIImageView *cellBottomLine = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, CELL_HEIGHT, 320.0, 1)];
cellBottomLine.image = [UIImage imageNamed:@"bottomCellImage.png"];
if (cellBottomLine.subviews) {
    [cell addSubview:cellBottomLine];
}

你为什么要运行那个 if 语句?如果你刚刚创建了一个新的图像视图,它每次都会返回YES(假设子视图数组默认不是nil)。您宁愿检查单元格的子视图中是否已经存在底部单元格图像。但我们甚至不需要这样做。只需在cellForRowAtIndexPath: 方法中添加图像,在!cell if 中。这样,我们只在尚未创建单元格的情况下添加bottomCellImage

if (!copyButton.superview) 电话也是如此。在 cellForRowAtIndexPath: 方法中继续我们离开的地方:

        UIImageView *cellBottomLine = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, CELL_HEIGHT, 320.0, 1)];
        cellBottomLine.image = [UIImage imageNamed:@"bottomCellImage.png"];
        [cell addSubview:cellBottomLine];

        copyButton = [BSFunctions createButtonWithNormalImageNamed:@"copyCellButton.png"
                                      highlightedImageName:@"copyCellButtonPressed.png"
                                                    target:self
                                                  selector:@selector(copyPressedFromCell:)];
        [copyButton setFrame:CGRectMake(250, 10, 62, 32.5)];
        copyButton.tag = indexPath.row;
        [cell addSubview:copyButton];
    }

    UIButton *button = [cell viewWithTag:indexPath.row]; // Get the copy button
    // Update the state of the button here based on CellIdentifier, outside the if statement so that it gets updated no matter what
    // Also configure your cell with any non-button related stuffs here

    return cell;
}

【讨论】:

  • 为什么要创建两次cellBottomLine 图像?代码后面哪里需要buttonStates
  • @SergiusGee 我没有创建两次,我引用了您的代码来向您展示如何更改它。我解释了在代码的其他地方使用 buttonStates 的位置。
  • 我的错。谢谢你的解释,我试试看!
  • @SergiusGee 没问题,让我知道您的结果是什么,我没有时间制作示例应用程序并自己进行测试。 :)
  • 即使我将copyButton.highlighted = YES 设置为UIButton *button = [cell viewWithTag:indexPath.row] 所在的行,如果表格滚动出来,它仍然不会突出显示。它开始让我发疯了
【解决方案4】:

为了完全避免这种情况,为什么不继承 UITableViewCell 并在故事板/XIB 中创建该类的指定表示?这样,当单元被重用时,操作系统不会一次又一次地创建 UI 元素,而是重用已经从 IBOutlets 分配的元素。

【讨论】:

  • 我不使用 XIB 或 Storyboards
  • 作为一项规则?一个原则?什么意思?
  • 这是我很久以前问过的一些相关问题,只是为了确保我能分享你的愤怒stackoverflow.com/questions/11538510/…
  • @SergiusGee 好吧,如果那是你想要做的,你做错了:) - 你应该创建一个新类,例如将其称为 BSButtonCell 并使其继承自 UITableViewCell。在初始化程序或 BSButtonCell 的 -layoutSubviews 方法中配置按钮/图像的框架。从视图控制器中删除 -tableView:willDisplayCell:atIndexPath: 方法。配置-tableView:cellForRowAtIndexPath:中按钮的动作方法。
  • @SergiusGee 好的设计和复杂性几乎总是在创建应用程序的第一阶段发生冲突。当出现错误或性能问题时,糟糕的设计就会再次困扰您。
【解决方案5】:
you can check it in this way:
1) put somewhere `copyButton = nil;` (in viewDidLoad, or somewhere else;
2) then:
- (UITableViewCell *)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {

        UIImageView *cellBottomLine = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, CELL_HEIGHT, 320.0, 1)];
        cellBottomLine.image = [UIImage imageNamed:@"bottomCellImage.png"];
    if (cellBottomLine.subviews) {
        [cell addSubview:cellBottomLine];
    }
    if (!copyButton) {
        copyButton = [BSFunctions createButtonWithNormalImageNamed:@"copyCellButton.png" highlightedImageName:@"copyCellButtonPressed.png" target:self selector:@selector(copyPressedFromCell:)];
        [copyButton setFrame:CGRectMake(250, 10, 62, 32.5)];
        copyButton.tag = indexPath.row;
        if (!copyButton.superview) {
           [cell addSubview:copyButton];
        }
     }

    return cell;
}

【讨论】:

  • 不幸的是它不起作用,它只在第一个单元格中创建一个按钮
【解决方案6】:

按以下方式试试

if ([cell viewWithTag:LBL_TAG])
{
    UIView *vi = (UIView*)[cell viewWithTag:LBL_TAG];
    if ([vi isKindOfClass:[UILabel class]])
    {
        UILabel *lbl = (UILabel*)vi;
        NSLog(@"test  %@..",lbl.text);
    }
}

希望对你有帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-13
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 2015-05-05
    • 1970-01-01
    相关资源
    最近更新 更多