【问题标题】:UITableViewController return to next text field in CellUITableViewController 返回到单元格中的下一个文本字段
【发布时间】:2020-01-25 16:44:39
【问题描述】:

我有一个 UITableViewController 和一个实现 UITableView 的类。

@interface CreateEditViewController : UITableViewController<UITextFieldDelegate>

@end

我还有一个实现 UITableViewCell 的类,每个 Cell 都包含一个文本字段。

@interface CreateEditCell : UITableViewCell
@property (weak, nonatomic) IBOutlet UITextField *celltextfield;


@end

在我的 TableView 控制器类中,我实现了三个方法 cellForRowAtIndexPathnumberOfRowsInSectiontextFieldShouldReturn

在我的cellForRowAtIndexPath 中,我将每个单元格的文本字段委托分配给 self,并在 switch case 中给每个单元格一个标签。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    CreateEditCell* cell = nil;
    cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
    cell.celltextfield.delegate = self;
    cell.celltextfield.returnKeyType = UIReturnKeyNext;

    switch (indexPath.row) {

        case 0:

            cell.celltextfield.tag = 0;
            break;
        case 1:
            cell.celltextfield.tag = 1;
            break;
        case 2:
            cell.celltextfield.tag = 2;
            break;
        case 3:
            cell.celltextfield.tag = 3;
            break;
    }
    return cell;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return 4;
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField{
    NSInteger nexttag = textField.tag+1;
    UIResponder* nextresponder = [textField.superview viewWithTag:nexttag];
    if(nextresponder){
        [nextresponder becomeFirstResponder];
    }else{
        [textField resignFirstResponder];
        NSLog(@"Nothing to return to");
    }


    return NO;
}

因此,返回下一个文本字段在我之前的设计中有效,我没有由单元格动态生成文本字段。相反,我在故事板上有单独的文本字段,并在 viewdidload 中分配了它们的标签。但是现在使用当前的设计,当我点击返回按钮而不是转到下一个单元格时,它只会打印“Nothing to return”,这没有意义,因为我有四个单元格(四个文本字段),每个单元格都有自己的独特的标签。所以我的问题是,如何使用我拥有的当前设计返回下一个文本字段。

【问题讨论】:

    标签: ios objective-c uitableview


    【解决方案1】:

    问题是您的设计更改也导致您的文本字段的视图层次结构更改。它们不再是直接的兄弟姐妹,而是托管在表格视图中的单元格中。 因此,当您关注一个新的文本字段时,您必须找到承载该文本字段的单元格,而且,该单元格可能不可见,因此您需要先滚动到它。

    因此:

    - (BOOL)textFieldShouldReturn:(UITextField *)textField{
        NSInteger nexttag = textField.tag+1;
        if (nexttag < [self.tableView numberOfRowsInSection:0]) {
            NSIndexPath *nextIndexPath = [NSIndexPath indexPathForRow:nexttag inSection:0];
            [self.tableView scrollToRowAtIndexPath:nextIndexPath atScrollPosition:UITableViewScrollPositionNone animated:YES];
            CreateEditCell* cell = [self.tableView cellForRowAtIndexPath:nextIndexPath];
            if (cell == nil) {
                // cell is not displayed at the moment, therefore we 
                // "force-scroll" (without animation) to it
                // and then retrieve it again:
                [self.tableView scrollToRowAtIndexPath:nextIndexPath atScrollPosition:UITableViewScrollPositionNone animated:NO];
                cell = [self.tableView cellForRowAtIndexPath:nextIndexPath];
            }
            [cell.celltextfield becomeFirstResponder];
        }else{
            [textField resignFirstResponder];
            NSLog(@"Nothing to return to");
        }
    
        return NO;
    }
    

    这段代码有点又快又脏,因为如果单元格不可见,则无法通过调用cellForRowAtIndexPath 来检索它。即使是动画scrollToRowAtIndexPath 也无济于事,因为您需要等待单元格显示。所以我的解决方法只是再次滚动,没有动画。

    更好的解决方案是实现UIScrollViewDelegate,然后在scrollViewDidEndScrollingAnimation 中,您可以聚焦文本字段——但请注意,只有在滚动是由textFieldShouldReturn 而不是由用户滚动活动。所以你可以使用一个标志(或者更好:一个自定义委托/闭包),你可以检查它以确定哪种滚动动画结束了。

    【讨论】:

    • 是的,所以我的主要问题是,当我想输入 UITextField 时,有时键盘会覆盖文本字段。我读到在单元格内使用带有文本字段的 UITableView 会导致表格在我更改为不同的文本字段时向上滚动。我会尝试上面的解决方案,如果我不能让它工作,我会试试你的。编辑:您的解决方案确实适用于将来阅读的人。我选择了上面的解决方案,因为它更简单,而且只更改了一行代码!谢谢。
    • 嗯,我认为每个单元格都有自己的文本字段,textFieldShouldReturn 应该关注下一个文本字段(在下一个单元格中)——它可能不可见,因此没有 viewForTag存在。但也许我想得太远了:-)
    • 在我当前的设计中,单元格永远不会为空,因为触发 textFieldShouldReturn 的唯一方法是用户明确按下单元格,特别是其中的文本字段。在这种情况下,cellForRowAtIndexPath 已经分配了单元格。
    • 不,你是对的@AndreasOetjen - 这是我在回答中遗漏的内容。下一个单元格绝对有可能不可见,因此在调用 viewWithTag: 之前需要进行某种滚动。
    • @AndreasOetjen 你完全正确,除非你滚动,否则某些单元格将不可见。我想我可能不必担心这一点,因为我创建的单元格数量可能总是可见的。但绝对要记住一些事情。
    【解决方案2】:

    我很确定问题出在这条线上:

    UIResponder* nextresponder = [textField.superview viewWithTag:nexttag];
    

    textField.superview 指的是包含textField 的单元格的contentView。其他文本字段不是 contentView 的后代(也不是单元格本身),因此在其上调用 viewWithTag: 将始终为其他文本字段的标签返回 nil。

    调用viewWithTag: 时,您需要在视图层次结构中上移才能找到其他文本字段。 self.viewself.tableView(它们都引用同一个视图,因为这个视图控制器是 UITableViewController 的子类)应该可以工作:

    UIResponder* nextresponder = [self.tableView viewWithTag:nexttag];
    

    另外(与您的实际问题无关),您可以简化以下内容:

    switch (indexPath.row) {
        case 0:
            cell.celltextfield.tag = 0;
            break;
        case 1:
            cell.celltextfield.tag = 1;
            break;
        case 2:
            cell.celltextfield.tag = 2;
            break;
        case 3:
            cell.celltextfield.tag = 3;
            break;
    }
    

    只写一行:

    cell.celltextfield.tag = indexPath.row;
    

    还有一个不相关的点:我建议在你的文本字段标签上添加一些偏移量,而不是从零开始,因为零是 all 视图的默认标签,所以你将无法区分使用viewWithTag: 时,来自tableViewtableView 的单元格、单元格的contentViews 等视图的第一个文本字段(因为它的标签为 0)。比如:

    cell.celltextfield.tag = indexPath.row + 1;
    

    【讨论】:

    • 感谢您实际上提到我可以通过将标签分配给行来简化标签!所以我认为self.tableView已经存在,因为它实现了UITableView?编辑:所有这些建议都奏效了,谢谢!
    • 是的,tableViewUITableViewController 上的一个属性,所以你的子类可以访问它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多