简体   繁体   English

UITableView中的iOS6和屏幕外UITextView

[英]iOS6 and offscreen UITextView in UITableView

I have a UITableViewController that has a UITextField in each cell. 我有一个UITableViewController,每个单元格中都有一个UITextField。 When the user hits return in a field, it automatically sets the next field to be first responder and scrolls the table to show that field, like this: 当用户在字段中点击返回时,它会自动将下一个字段设置为第一个响应者,并滚动表格以显示该字段,如下所示:

- (BOOL) textFieldShouldReturn:(UITextField *)textField 
{  
    UITextField *nextTextField=nil;
    NSInteger row;
    NSInteger section;

    if(textField == self.txtFieldA) 
    {
        nextTextField = self.txtFieldB;
        row=1; section=0;
    }
    else if(textField == self.txtFieldB) 
    {
        nextTextField = self.txtFieldC;
        row=2; section=0;
    }
    else 
    {
        [textField resignFirstResponder];
    }

    if(nextTextField) 
    {        
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
        [nextTextField becomeFirstResponder];

        [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];      
    }
}

The issue comes when you select a text field (say txtFieldA), scroll the table down so that txtFieldB is not visible, then hit enter. 当您选择文本字段(例如txtFieldA),向下滚动表格以使txtFieldB不可见时,会出现问题,然后按Enter键。 It works as expected on iOS5 (txtFieldB becomes the new first responder). 它在iOS5上按预期工作(txtFieldB成为新的第一响应者)。 However, on iOS6 it doesn't. 但是,在iOS6上却没有。 It scrolls to the correct spot in the table, but the txtFieldB does not become the first responder (and I'm not sure what is -- when I hit "Back" on my nav controller, the keyboard stays visible). 它滚动到表格中的正确位置,但是txtFieldB不会成为第一个响应者(我不确定是什么 - 当我在导航控制器上点击“返回”时,键盘保持可见)。

When I hit "Return", txtFieldB's didBeginEditing isn't fired. 当我点击“返回”时,不会触发txtFieldB的didBeginEditing。 If I delay [nextTextField becomeFirstResponder] by a second or so (until the scrolling animation finishes which makes nextTextField visible) it works as expected, but it seems hacky and less smooth to do that so I would rather understand what's going wrong than implement something like that. 如果我延迟[nextTextField becomeFirstResponder]一秒钟左右(直到滚动动画结束,这使得nextTextField可见)它按预期工作,但它看起来很hacky并且不那么顺利,所以我宁愿理解什么是错误的,而不是实现像那。

In my solution to this problem, I subclassed UITableViewCell to make a text field cell. 在我对这个问题的解决方案中,我将UITableViewCell子类化为一个文本字段单元格。 In that text field cell, I overrode the -setSelected:animated: . 在那个文本字段单元格中,我覆盖了-setSelected:animated: .

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];

    if (selected) {
        [self.textField becomeFirstResponder];
    }
}

Back in my view controller, when I want to advance to the next field, I just select the row it's in. 回到我的视图控制器中,当我想要前进到下一个字段时,我只选择它所在的行。

- (IBAction)advanceToNextTextField
{
    NSIndexPath *indexPath = [self nextIndexPathFromIndexPath:self.indexPathOfActiveField];

    [self.tableView selectRowAtIndexPath:indexPath
                                animated:YES scrollPosition:UITableViewScrollPositionNone];
    [self.tableView scrollToRowAtIndexPath:indexPath
                          atScrollPosition:UITableViewScrollPositionNone animated:YES];
}

This makes handling the the return key easy. 这使得返回键的处理变得容易。

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    switch (textField.returnKeyType) {
        case UIReturnKeyNext: [self advanceToNextTextField]; break;
        case UIReturnKeyDone: [self resignFirstResponder]; break;
        default:              break;
    }

    return YES;
}

Hope that helps. 希望有所帮助。

I also have an existing project that worked fine prior to iOS 6. My universal app uses a UITableView to create a form with "next" and "previous" buttons on a keyboard toolbar (similar to Safari). 我还有一个在iOS 6之前工作正常的项目。我的通用应用程序使用UITableView在键盘工具栏上创建一个带有“下一个”和“上一个”按钮的表单(类似于Safari)。 The table displays instances of a UITableViewCell subclass that contains a text field. 该表显示包含文本字段的UITableViewCell子类的实例。 The next/previous functionality also wraps - so "next" for the last field returns focus to the top of the form. 下一个/上一个功能也包装 - 所以最后一个字段的“next”将焦点返回到表单的顶部。

Unfortunately, Jeffrey Thomas' solution isn't quite working for me. 不幸的是,Jeffrey Thomas的解决方案并不适合我。 If a cell is offscreen, the select-and-scroll method in advanceToNextField method works fine for the cell itself. 如果单元格在屏幕外,则advanceToNextField方法中的select-and-scroll方法适用于单元格本身。 In the setSelected method, the view hierarchy for the text field is correct: UITextField -> UITableViewCellContentView -> UITableViewCell subclass -> UITableView . setSelected方法中,文本字段的视图层次结构是正确的: UITextField - > UITableViewCellContentView - > UITableViewCell子类 - > UITableView

However, the becomeFirstResponder call is still failing to activate the field's editing mode, fire textFieldDidBeginEditing , etc. The keyboard is still visible but doesn't affect the now-visible cell. 但是, becomeFirstResponder调用仍然无法激活字段的编辑模式,触发textFieldDidBeginEditing等。键盘仍然可见但不影响现在可见的单元格。

For now, the only way that I've been able to circumvent this issue is to scroll first without animation : 现在,我能够绕过这个问题的唯一方法就是首先滚动没有动画

[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionNone animated:NO];
[self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone];

Like Ned's delay technique in the op, this ensures that the text field is visible when the app asks it to respond. 就像操作中的Ned延迟技术一样,这确保了当应用程序要求它响应时文本字段是可见的。 Otherwise, it seems that becomeFirstResponder is firing during the animation & before the text field is (fully) visible. 否则,似乎在动画期间和文本字段(完全)可见之前, becomeFirstResponder正在触发。 Apparently some changes in iOS 6 are more strict on first responder messages and visibility! 显然,iOS 6中的一些更改对第一响应者消息和可见性更严格!

Sadly, this loses the nice fluid animation when moving from field to field. 可悲的是,当从田地移动到田野时,这会失去漂亮的流畅动画。 Assuming this isn't simply a bug in iOS 6.0, I plan on moving away from using UITableView as a form in the future. 假设这不仅仅是iOS 6.0中的一个错误,我计划将来不再使用UITableView作为表单。

Figured out a solution to this problem, with the help of my coworker Charles (thanks!). 在我的同事查尔斯(谢谢!)的帮助下找出了解决这个问题的方法。 I also tried Jeffrey Thomas's solution (and variations of it) with no luck: the text field does not become first responder if its table cell is offscreen, as described by Ogel as well. 我也尝试过杰弗里·托马斯的解决方案(及其变体)没有运气:如果表格单元格在屏幕外,文本字段也不会成为第一响应者,如Ogel所描述的那样。 I looked for UITableViewDelegate methods that would alert me to when the tableview is done animating and delay calling the text field's setSelected: method until then, with no luck. 我查找了UITableViewDelegate方法,这些方法会在tableview完成动画时提醒我并延迟调用文本字段的setSelected:方法,直到那时,没有运气。 Then he pointed me to 然后他指着我

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView

which is also fired by the table view ( UITableViewDelegate conforms to UIScrollViewDelegate ), when it is done scrolling in response to the table view method 这也是表视图触发的( UITableViewDelegate符合UIScrollViewDelegate ),当它完成滚动以响应表视图方法时

- (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated

So the key is to calculate the index path of the row you intend to select in your next/previous method (like in Jeffrey Thomas's - (IBAction)advanceToNextTextField method), but instead of selecting it, just scroll to it, and set an ivar for it: 所以关键是要计算你想要在下一个/上一个方法中选择的行的索引路径(比如Jeffrey Thomas的- (IBAction)advanceToNextTextField方法),但是不要选择它,只需滚动到它,然后设置一个ivar为了它:

[_table scrollToRowAtIndexPath:nextIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
_selectIndexPathOnAnimationEnd = nextIndexPath;

Then in the scroll view delegate method, select the row at that index path after the table view has finished scrolling to it: 然后在滚动视图委托方法中,在表视图完成滚动后,在该索引路径中选择该行:

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
    if(_selectIndexPathOnAnimationEnd != nil) {
        [_table selectRowAtIndexPath:_selectIndexPathOnAnimationEnd animated:NO scrollPosition:UITableViewScrollPositionMiddle];
        _selectIndexPathOnAnimationEnd = nil;
    }
}

At this point the text field can become first responder. 此时,文本字段可以成为第一响应者。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM