带有 canBecomeFirstResponder YES 的自定义 UITableViewCell 不会在屏幕外取消选择

Posted

技术标签:

【中文标题】带有 canBecomeFirstResponder YES 的自定义 UITableViewCell 不会在屏幕外取消选择【英文标题】:Custom UITableViewCell with canBecomeFirstResponder YES won't deselect when offscreen 【发布时间】:2013-02-18 11:41:36 【问题描述】:

我最近碰巧在 UITableView 中发现了一些关于选择和取消选择功能的有趣错误。 (m.b. 这本身不是一个错误,但我觉得这种情况非常反常)。

史前史:我正在尝试创建一些自定义 TableViewCell 类,该类将能够使用 UIDatePicker 选择一些日期并将其放置在单元格的标签中。 "CellDate" sample 对我来说不是很好。所以我试图将一些自定义 inputView 设置为单元格并使其成为第一响应者。 After some time of researches I found the way to override readonly inputView property of my custom UITableViewCell subclass, and now it works perfectly: when the cell is selected I call [self becomeFirstResponder] on it and when the cell is deselected I call [self resignFirstResponder] so它工作得很好,但有一些错误。

当我在屏幕上显示我的自定义单元格时(即没有滚出屏幕)一切都是正确的,但如果我选择它

向下滚动 tableView,使我的单元格不再出现在屏幕上

然后选择另一个单元格

我的自定义单元格不会被取消选择

.

默认 UITableViewCell 功能的唯一主要变化是:

- (void)setSelected:(BOOL)selected animated:(BOOL)animated

    [super setSelected:selected animated:animated];

    if (selected)
    
        [self becomeFirstResponder];
    
    else
    
        [self resignFirstResponder];
    


- (BOOL)canBecomeFirstResponder

    return YES;

仅使用此方法覆盖会出现此错误:当当前选择的自定义单元格不在屏幕上时,它不会因某种原因取消选择。

我的问题是:有没有人经历过这样的事情,有什么我可以做的吗?因为除此之外,我对日期单元格的问题有一个完美的解决方案。

这不是使用 UITableViewCells 的正确方法吗?我做错了什么吗?我刚开始学习ios,所以我可能对它的某些方面不是很熟悉。

附:抱歉我的语言不好,我不是以英语为母语的人。

更新:

我发现了更多细节。经过一些研究,我发现,当您滚动 tableView 并在屏幕外隐藏一些 tableViewCell 时,它的(单元格)正在被破坏。当您向后滚动时,它会通过调用 tableView 的委托的 tableView:cellForRowAtIndexPath 再次创建: 除此之外,如果您尝试为行的 indexPath 调用 [tableView cellForRowAtIndexPath:indexPath],即在屏幕外,tableView 将返回 nil。

但奇怪的是:当您的自定义单元格是 firstResponder 时,显然,它不会通过 tableView 的委托的 tableView:cellForRowAtIndexPath: 重新创建,也无法通过 [tableView cellForRowAtIndexPath:indexPath] 访问。

对我来说,这很奇怪。

【问题讨论】:

【参考方案1】:

为了直接回答这个问题,UITableView 不会自行取消选择单元格。在 TableView 的控制器中,您需要覆盖 -(void)tableView:(UITableView *)tableView didselectRowAtIndexPath:(NSIndexPath *)indexPath 并手动取消选择选定的单元格。

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

    [tableView deselectRowAtIndexPath:indexPath animate:YES];

(抱歉编辑,我在回答时不小心保存了)

在 UITableViewCell 的子类中,您应该覆盖 -(void)setEditing:(BOOL)editing animated:(BOOL)animated 以便将单元格转换为可编辑状态。 (将您的 UITextField 设置为可编辑),然后在您的单元格中,您将使您的文本框成为/辞职第一响应者。

First responder 用于成为可编辑时响应键盘的下一个对象。

例如,如果您有单元格 c1 和单元格 c2。 c1 和 c2 中都有 UITextFields。您在 c1 中,并且您希望键盘上的 Return 按钮将文本光标移动到 c2 中,然后当 c1 时,需要让 UITextField 作为第一响应者,并告诉 c2 使其 UITextField 成为第一响应者。 您可以通过使自定义单元格成为其 UITextField 的代表来实现此目的,然后实现 -(BOOL)textFieldShouldReturn:(UITextField *)textField 以使 textField 成为第一响应者,然后您将告诉 UITableView 的控制器告诉下一个单元格使其文本字段成为第一响应者。

【讨论】:

感谢您的回答。如我所见,默认的 tableView 行为是在选择其他单元格时取消选择先前选择的单元格。我将尝试覆盖 tableView:didSelectRowAtIndexPath:,但在我看来,默认行为已损坏。 另外,我真的必须使用 UITextField 吗?这实际上不是我想要使用的,因为我的单元格中本身没有文本字段,整个单元格是一个控制元素,它根据所选日期更改其标签内容。而且我对编辑 UITableViewCell 的状态也不感兴趣,因为单元格不会改变它的状态。我现在唯一需要的是正确选择/取消选择单元格 我好像找到了更多细节,我会更新问题【参考方案2】:

我自己找到了解决方案。 It appears to be as simple as resigning first responder when other row is being selected.顺便说一句,我使用this answer 来完成此操作。

希望它可以帮助某人。

【讨论】:

以上是关于带有 canBecomeFirstResponder YES 的自定义 UITableViewCell 不会在屏幕外取消选择的主要内容,如果未能解决你的问题,请参考以下文章

UITabBarController canBecomeFirstResponder 方法未被调用

ViewController canBecomeFirstResponder iOS 8

ios - 带有 UITextView 的 UITapGestureRecognizer

了解第一响应者的系统逻辑

KeyboardDidShow 触发太频繁?

运动开始:不工作