UITableViewCell 与 UITextField 失去选择 UITableView 行的能力?

Posted

技术标签:

【中文标题】UITableViewCell 与 UITextField 失去选择 UITableView 行的能力?【英文标题】:UITableViewCell with UITextField losing the ability to select UITableView row? 【发布时间】:2011-07-05 08:36:08 【问题描述】:

我几乎完成了实现一个带有UITextFieldUITableViewCell。而不是通过CGRectMakeUITableViewCell.contentView 我已经实现了它更简单的方式:

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

    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"Cell"];
    [cell setSelectionStyle:UITableViewCellSelectionStyleBlue];
    amountField = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 190, 30)];
    amountField.placeholder = @"Enter amount";
    amountField.keyboardType = UIKeyboardTypeDecimalPad;
    amountField.textAlignment = UITextAlignmentRight;
    amountField.clearButtonMode = UITextFieldViewModeNever; 
    [amountField setDelegate:self];

    [[cell textLabel] setText:@"Amount"];
    [cell addSubview:amountField];
    return cell;

然后我还实现了didSelectRow 方法,将 textField 重新签名以允许显示其他字段的输入视图。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

    ...
    [amountField resignFirstResponder];
    ...

这很顺利,唯一的问题是表格中还有其他行,当其他行被选中时,整个单元格被选中并变为蓝色,而我的 UITextField 没有,我的意思是该字段被选中并且我可以输入文本但单元格未被选中。 我已经测试过了,发现问题出在这条线上:

[cell addSubview:amountField];

这似乎破坏了可选择的单元格行为,甚至将其添加到[cell contentView] 也无法解决此问题。我错过了什么吗?

【问题讨论】:

【参考方案1】:

如果文本字段的 userInteractionEnabled 设置为 YES,并且它填满了整个单元格,则无法让单元格监听触摸。为了让单元格响应触摸,您需要将文本字段的 userInteractionEnabled 设置为 NO

编辑:如果你想让文本字段可编辑,当单元格被选中时,在didSelectRowAtIndexPath:方法中添加以下代码,

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 

    // get the reference to the text field
    [textField setUserInteractionEnabled:YES];
    [textField becomeFirstResponder];

【讨论】:

如果你设置userInteractionEnabled = NO; 这不会使 UITextField 不可编辑吗? 显然不是:我已遵循 EmptyStack 的建议并设置 [amountField setUserInteractionEnabled:NO];在 DidSelectRow 方法的开头,然后 [amountField setUserInteractionEnabled:YES] 仅当所选行是带有文本字段的行时。选择现在可以了,但我必须在该行上点击两次才能实际输入文本... @micpringle,当然。当文本字段填充单元格时,他不能同时让文本字段和单元格响应触摸。 @Fabrizio Prosperi,您无需在单元格上点击两次。您可以在didSelectRowAtIndexPath: 方法中的[amountField setUserInteractionEnabled:YES] 行之后调用[amountField becomeFirstResponder] 感谢 EmptyStack 成功了,您的解决方案在这里最简单且运行顺利!【参考方案2】:

添加子视图并没有破坏任何内容,而是 UITextField 在 UITableViewCell 之前捕获触摸。您可以通过在 UITextField 之外但在 UITableViewCell 范围内点击来测试它,您会发现它实际上仍然按照您的预期进行选择。

要解决这个问题,您可以继承 UITextField 并添加一个 UITableView 属性。在实例化 UITextField 并将其添加到单元格时设置属性。

amountField.tableView = tableView;

然后你需要在你的子类中重写 becomeFirstResponder,并在方法中使用 UITextField 获取单元格的行,然后手动选择它

- (BOOL)becomeFirstResponder

    // Get the rect of the UITextView in the UITableView's coordinate system
    CGRect position = [self convertRect:self.frame toView:self.tableView];
    // Ask the UITableView for all the rows in that rect, in this case it should be 1
    NSArray *indexPaths = [self.tableView indexPathsForRowsInRect:position];
    // Then manually select it
    [self.tableView selectRowAtIndexPath:[indexPaths objectAtIndex:0] animated:YES scrollPosition:UITableViewScrollPositionNone];
    return YES;

【讨论】:

这也有效,但它需要很多额外的代码,而按照 EmptyStack 下面的建议设置文本字段 userInteractionEnabled=NO 是几行代码......至少在我找到之前其他一些问题:) 谢谢你的帮助,它使问题更清楚了。 这不是保留循环吗? tableView -> visibleCells -> amountField -> tableView @jakenberg true,amountField 上的 tableView 属性应指定为 weak 以避免潜在的保留周期 别忘了打电话给[super becomeFirstResponder];【参考方案3】:

第一件事是您没有使用可重复使用的单元格。您提供的编码会占用大量内存。

接下来您可以通过触摸文本字段以外的区域来选择行。

您的问题的一个解决方案是

在您的文本字段代表中

UITableViewCell *cell = (UITableViewCell *)[textField superView];
cell.selected=YES; //I think this will call the didSelectRowATIndex;

我不确定这是否可行。不过值得一试。

【讨论】:

除了这个表是 4 个单元格只是因为它是一个很好的输入掩码,所以内存不应该是一个大问题,但你为什么说我没有使用可重复使用的单元格?我以为我做到了。我现在要试试你的解决方案。谢谢。 我认为您误解了可重复使用的概念。请参见此处developer.apple.com/library/ios/#documentation/UserExperience/…... 无论如何 4 个单元格是可以的,但如果一行超过 10 个单元格就会给您带来问题。 我当然可能误解了,但是当单元格内部都有不同的控件时,是否应该避免重复使用单元格?无论如何感谢您的链接:) 我也尝试了您的解决方案,在 textFieldShouldBeginEditing 中实现,它可以工作,但需要其他代码在选择其他单元格时取消选择单元格。无论如何是一个很好的提示。谢谢。【参考方案4】:

首先你需要为cellForRowAtIndexPath使用reuseIdentifier,如果你不使用reuseIdentifier的原因是:当你上下滚动时,它总是会分配新的单元格和新的文本字段,所以你需要把cell==nil条件,所以修改后的代码在这里:

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

  static NSString *reuseIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if (cell==nil) 
    cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier] autorelease];

     UITextField *amountField = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 190, 30)];
     amountField.placeholder = @"Enter amount";
     amountField.keyboardType = UIKeyboardTypeDecimalPad;
     amountField.textAlignment = UITextAlignmentRight;
     amountField.clearButtonMode = UITextFieldViewModeNever; 
     [amountField setDelegate:self];
     [cell.contentView addSubview:amountField];

[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
[[cell textLabel] setText:@"Amount"];

return cell;

在 didSelect 委托方法中你可以这样做

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

  [prevField resignFirstResponder];
  UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
  UIView *view = [[cell.contentView subviews] lastObject];
  if([view isKindOfClass:[UITextField class]]
     currentField = (UITextField*)view;
  
  [currentField becomeFirstResponder];
  prevField = currentField;

【讨论】:

伙计们,我感谢您为教授 Cocoa 最佳实践所做的努力,但我试图将唯一相关的代码放在那里,amountField 不是每次都实例化,而是仅在视图中加载,检查 !cell 是在那里,但我省略了,因为与我的问题无关,而且我的表格不会滚动,因为它只有 4 行。不过,其余的 cmets 非常有帮助。谢谢!【参考方案5】:

在索引路径行的单元格内添加以粗体给出的这一行,

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"Cell"];
    [cell setSelectionStyle:UITableViewCellSelectionStyleBlue];

    amountField = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 190, 30)];
    amountField.placeholder = @"Enter amount";
    amountField.keyboardType = UIKeyboardTypeDecimalPad;
    amountField.textAlignment = UITextAlignmentRight;
    amountField.clearButtonMode = UITextFieldViewModeNever; 

    [amountField setDelegate:self];
    [[cell textLabel] setText:@"Amount"];

    **for (UIView *cellSubViews in cell.subviews) 
            cellSubViews.userInteractionEnabled = NO;
    **

    [cell addSubview:amountField];
    return cell;

试试这个,它会起作用的

【讨论】:

以上是关于UITableViewCell 与 UITextField 失去选择 UITableView 行的能力?的主要内容,如果未能解决你的问题,请参考以下文章

UITableViewCell 与 UITextField 失去选择 UITableView 行的能力?

自定义uitableviewcell时,registerNib与registerClass的区别(转载)

UIMenucontroller 与 uitableviewcell 上的 uitextview

UITableViewCell 中的 UIStackView 与多行 UILabel

UITableViewCell 与 UIScrollView 防止单元格触摸

UITableViewCell的选中时的颜色及tableViewCell的selecte与deselecte