【问题标题】:tableviews cells are changing after scrolling down向下滚动后,tableviews 单元格正在更改
【发布时间】:2012-12-14 10:46:24
【问题描述】:

我正在分组的表格视图中制作表格。在这种形式中,我有 UIswitches 和文本字段。但是向下滚动后,单元格样式发生了变化。

这是我的 cellForRowAtIndex

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = nil;
    static NSString *MyIdentifier = @"GenericCell";
    cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] ;
    }
        NSString *text = nil;

    if(indexPath.section == CREDENTIALS_SECTION){
        if (indexPath.row == 0) {
            NSLog(@"tot hier login");
            UITextField *login = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
            login.adjustsFontSizeToFitWidth = YES;
            login.placeholder = @"example@gmail.com";
            login.keyboardType = UIKeyboardTypeEmailAddress;
            login.returnKeyType = UIReturnKeyNext;
            login.backgroundColor = [UIColor clearColor];
            login.tag = 0;
            login.delegate = self;

            [login setEnabled: YES];

            [cell addSubview:login];
        }else if (indexPath.row == 1){
            NSLog(@"tot hier pass");
            UITextField *pass = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
            pass.adjustsFontSizeToFitWidth = YES;
            pass.placeholder = @"Required";
            pass.keyboardType = UIKeyboardTypeDefault;
            pass.returnKeyType = UIReturnKeyDone;
            pass.secureTextEntry = YES;

            pass.backgroundColor = [UIColor clearColor];
            pass.tag = 0;
            pass.delegate = self;
            [cell addSubview:pass];
        }

        if (indexPath.row == 0) { // Email
            text = @"Email";
        }
        else if(indexPath.row == 1) {
            text = @"Password";
        }
    }else  if(indexPath.section == METHODS_SECTION){
        UISwitch *toggleSwitch = [[UISwitch alloc]initWithFrame:CGRectMake(220, 10, 100, 30)];
        toggleSwitch.tag = indexPath.row;
        [toggleSwitch addTarget:self action:@selector(toggleSwitched:) forControlEvents:UIControlEventValueChanged];
        [cell addSubview:toggleSwitch];

        if (indexPath.row == 0) { // Web
            text = @"Web applicatie";
        }
        else if(indexPath.row == 1) { //Mobile
            text = @"Mobiele applicatie";
        }
        else if(indexPath.row == 2) { //Mail
            text = @"E-mail";
        }


    }else  if(indexPath.section == PHONE_SECTION){
        UITextField *phoneText = [[UITextField alloc] initWithFrame:CGRectMake(20, 10, 185, 30)];
        phoneText.adjustsFontSizeToFitWidth = YES;
        phoneText.font = [UIFont fontWithName:@"Arial-BoldMT" size:18];
        phoneText.keyboardType = UIKeyboardTypeNumberPad;
        phoneText.delegate = self;
        phoneText.textColor = [UIColor blackColor];
        phoneText.text = _person.phone;
        [cell addSubview:phoneText];


    }else  if(indexPath.section == REMARK_SECTION){
        UITextView *textView = [[UITextView alloc]initWithFrame:CGRectMake(20, 10, 280, 260)];
        textView.text = _person.remark;
        textView.delegate = self;
        textView.font = [UIFont fontWithName:@"Arial" size:15.0];
        textView.backgroundColor = [UIColor clearColor];

        [cell addSubview:textView];
        text = @"";


    }else  if(indexPath.section == BUTTON_SECTION){
        cell.backgroundColor = [UIColor redColor];
        text = @"test";

    }
    cell.textLabel.text = text;
    return cell;
}

经过一番搜索,我发现有更多人遇到这个问题。而问题就在于这段代码。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = nil;
    static NSString *MyIdentifier = @"GenericCell";
    cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] ;
    }
        NSString *text = nil;

但我没有找到解决方案。 希望任何人都可以提供帮助!

亲切的问候!

澄清

好的,您可以在这里看到我的表单的屏幕截图。下面我有一个红色的单元格(保存按钮),当我向下滚动时,其他单元格的背景是红色的。有些单元格,文本属性正在发生变化。

【问题讨论】:

  • 你能解释一下你的意思吗?但是向下滚动后,单元格样式正在改变。?谢谢。
  • 请更具体一点。究竟是什么以一种意想不到的方式发生了变化。您期望什么以及会发生什么?
  • 我已经用截图编辑了我的问题
  • 你可以试试我下面的答案,这可能对你有帮助吗???
  • 你是对的 Stef Geelen。问题在于 dequeueReusableCellWithIdentifier 重用单元格的部分。如果您在重用之前从该单元格中删除所有子视图,则此问题将解决..

标签: objective-c ios xcode uitableview


【解决方案1】:

那是行不通的。显然你还没有完全理解重用机制是如何工作的。

你是做什么的? 首先,您获取要重新使用的单元格。如果你得到一个 - 到目前为止,但问题来了。如果你没有得到一个,那么你创建一个新的。

当您创建了一个新项目时,即在用户开始滚动之前开始的情况,然后您根据部分和行添加一些 UIItems。我将解释为什么这实际上不是一件明智的事情。

然后用户滚动。细胞将从屏幕上消失,然后可供重复使用。然后,您将获取单元格以供重复使用。但是很可能这些单元格上已经有额外的 UI 项,因为您以前以这种方式使用过它们。在接下来的过程中,您将添加新的 UI 项,无论该单元格上是否已经存在其他 UI 项。

你能做什么:

  1. 创建您自己的自定义表格单元子类。您可能需要的每组附加 ui 项的一个子类。这可能是最简洁的方法。对于每个子类,使用不同的重用标识符 (!!!) 这就是我要推荐的! 但是,还有其他选择:

  2. 您仍然可以接受您的概念,但为每种类型的单元格发明一种单独类型的重用标识符,这些单元格上有某种类型的附加 ui 项。如果是这样,请确保这些 UI 项仅作为子视图创建并添加到代码的 if (cell == nil) 分支中。只创建一次,然后重新使用它们。单元重用 ID 可以是“email-display”、“email-input”、“password-display”、“password-input”、“switch”……

  3. 上述解决方案的差异是,计算行和部分 进入重用标识符。例如第 0 节的“cell-id-0.2”和 第 2 行 - 左右。但是你仍然必须确保你真的 重复使用额外的 UI 视图,不要每次都重新创建它们 当单元格充满数据时。另外,第一部分的布局会根据您是要输入密码和电子邮件还是仅显示它们而有所不同。您仍然必须处理这些变化。

  4. 如果单元格 == nil - 表示如果一个单元格被重复使用 - 然后首先从您之前添加的每个 UI 项中清除它。您可以通过在创建时以及在重用所有子视图并删除具有标签 99 的子视图时使用 - 比如说 99 - (任何不同于 0 的东西都应该做)标记您的 UIViews 来做到这一点。尽管如此,您可以坚持使用以下代码你已经做了。

【讨论】:

  • 首先感谢您的详细回答。但是你推荐什么解决方案?最佳实践方法是什么?
  • 解决方案 4 对您来说是最简单的,因为这样您就不必更改代码。推荐解决方案 1。一开始它确实带来了最大的工作量,但通过为您提供最多可维护和可重用的代码,这将得到回报。这是目前最多的工作,但对未来的工作最少。
  • 所以如果我对每个部分都理解正确,创建一个新的 UICustomTableViewCell?
  • @HermannKlecker 非常感谢您解释这个概念。我经常通过在重用时从单元格中删除所有子视图来解决这个问题。 +1 分享这个... :)
  • @StefGeelen,在您的情况下,每个单元格都有一个唯一的 ID,因为您使用了许多不同的布局。 (除非您选择第 4 号解决方案。在这种情况下,所有人都可以使用一个 ID。)但是,“方法”部分中的三个开关可以完美地使用一个通用 ID,并为所有三个开关提供一个通用 ID。
【解决方案2】:

最简单的解决方法是:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"GenericCell"] ;
    //some more code
    return cell;
}

这将删除 tableview 的可重用性,但由于它是一个有限的设置视图,它可以。我仍然建议从 Hermann Klecker 的解决方案中选择 1 或 2。

【讨论】:

    【解决方案3】:

    如果您还需要保持 UIControl 状态,请使用

    static NSString *MyIdentifier = [NSString stringWithFormat:@"GenericCell%d",indexPath.row];
    

    它将始终返回您唯一的表格行,您可以根据需要使用它。

    【讨论】:

      【解决方案4】:

      在重用之前尝试从单元格中删除所有子视图。试试代码:

      if (cell == nil) 
      {
          cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] ;
      }
      else
      {
         [cell.contentView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
      }
      

      【讨论】:

      • 它会为你工作。但它确实会消除所有子视图,包括标准文本标签。但至少在某些情况下,您确实使用标准文本标签。因此,如果您想应用此解决方案,则必须在需要的情况下添加常规文本标签。
      • @HermannKlecker Oké,我应该把上面的代码放在哪里?我应该使用 cell.textlabel.text = text 来解决这个问题吗?
      【解决方案5】:

      在单元格上添加子视图之前删除所有子视图。

      if (cell == nil)
      {
            cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault    reuseIdentifier:SimpleTableIdentifier]autorelease];
      }
      else 
      {
          //To remove the subview of cell.
          for (UIView *vwSubviews in [cell.contentView subviews])
          {
                  [vwSubviews removeFromSuperview];
          }
      }
      

      它可能会解决你的问题。

      【讨论】:

      • 这符合我的建议。 4. 只需确保只删除之前可能添加的内容。您可以使用标签来识别这些子视图。
      • 实际上这里只删除了 contentview 的子视图,所以不需要给标签,它对我来说很好。
      【解决方案6】:

      其实你这里有一些不好的代码。

      在方法上

      - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
      

      除非它不在if (cell == nil),否则你不应该初始化和使用任何

      -(void)addSubview:(UIView*)view 
      

      为什么?

      单元格是从 tableview 重用的视图。因此,如果您添加一些子视图,下次在重用单元格时,它将在其上添加更多子视图。只是它们重叠并可能导致 MEMORY LEAK。

      不要忘记细胞是可重复使用的。所以;

      如果我有以下代码,除非我没有在其他地方设置文本。预计所有单元格的文本标签中都有文本“这是一个文本”。因为它们是可重复使用的。

      if (someChangingBool) {
         cell.textLabel.text = @"this is a text"; 
      }
      

      所以我需要一个 else 来设置文本。

      对于more Information

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-12-18
        • 1970-01-01
        • 1970-01-01
        • 2021-11-20
        • 2017-01-08
        • 2012-09-10
        • 2015-11-19
        相关资源
        最近更新 更多