iOS7导航控制器pushViewController动画错误

3

看起来我发现了navigationController pushViewController方法中的一个bug。为了重现它,我拿取了示例master detail项目并对-didSelectRow:方法做了一些更改:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    DetailViewController* view = [self.storyboard instantiateViewControllerWithIdentifier: @"view"];
    NSDate *object = _objects[indexPath.row];
    [view setDetailItem:object];
    [self.detailViewController.navigationController pushViewController:view animated:YES];
}

我还将详细视图的故事板ID更改为“view”。以下是发生的情况:
当缓慢选择主控制器的任何行(推动动画完成时)时,它工作正常: selecting rows slowly 如果在动画仍在显示时选择任何行,则详细视图将变得无效(显示推方法之前调用的最后一行),只有导航栏显示新视图的推送动画: selecting rows rapidly 当这种情况发生时,您会在调试器输出中收到一些警告:
Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.

nested push animation can result in corrupted navigation bar

Unbalanced calls to begin/end appearance transitions for <DetailViewController: 0x8a6e070>.

这里有个棘手的问题:如果你回到详细视图的导航栏,然后在主表视图中选择不同的行,或者在详细视图中返回两次,应用程序会崩溃。
Can't add self as subview

但是,如果在iOS6上运行相同的代码,则没有任何问题或警告。

当前解决方案:

调用animated:NO方法似乎可以正常工作,显然没有推送动画。

另一种解决方案是在主页面中设置boolean值,并在从详细页面的viewDidAppear中将其设置为true。这样,您在调用push方法时可以检查该值。缺点是:如果您快速选择同一行,则tableView可能会出现滞后,如果您快速选择不同的行,则不会在详细信息中显示,但会在主表视图中被选中并突出显示,您可以保存所选行的索引并在代码中更改选择,但这会导致行突出显示闪烁。

这两个解决方案都涉及一些妥协,因此我希望找到另一种处理方式。有更好的解决方案吗?


听起来你对情况的理解和任何人一样。如果你有问题,请明确说明。如果你只是想为他人提供帮助性观察,你应该将其重写成问题形式,在答案中添加解决方案,并接受答案,以便清楚地表明你不需要别人花时间在这上面。此外,如果你还没有,你应该向苹果报告错误 - Caleb
抱歉,我本意是发布这个来寻找其他解决方法。 - Arnas
2个回答

5
经过测试发现,在ios6中,当选中tableview单元格并调用push时,tableview会将.allowsSelection设置为NO,直到推送结束。
在ios7中可以很容易地通过在didSelectRowAtIndexPath方法中设置.allowsSelection为NO,并在详细视图的didAppear:方法中添加回调来重现此问题,我们在主视图中将tableview的.allowsSelection设置为YES。
虽然这样做完全没有问题,但我发现当快速选择两个不同的单元格时,第二个单元格将被忽略,有点令人烦恼。
因此,我设置了一个功能,如果在推送动画未结束时选择了另一个单元格,我会保存对新视图的引用,并在第一个动画结束后立即推送它。通过这样做,我认为tableView的响应速度更快了一些。

1
您之所以出现问题是因为在另一个视图控制器没有完全推出时就进行了推送(日志已经警告您不要这样做)。
推送动画应该需要大约0.4秒的时间,因此用户必须足够快地在0.4秒内点击另一行,是的,这是可行的,但不是正常的行为。
您可以通过在-didSelectRow:方法中使用以下代码来编辑动画时间小于0.4秒(可能是0.1或0.2)。
DetailViewController* view = [self.storyboard instantiateViewControllerWithIdentifier: @"view"];
NSDate *object = _objects[indexPath.row];
[view setDetailItem:object];

[UIView  beginAnimations:@"ShowDetails" context: nil];
[UIView setAnimationCurve: UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.2];
[self.detailViewController.navigationController pushViewController:view animated:NO];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:self.navigationController.view cache:NO];
[UIView commitAnimations];

希望有所帮助 :)

侧边的推入动画在我的应用中更加合理,所以我选择了它而不是这个,但其他应用可能更喜欢使用UIViewAnimations,因为它更容易处理动画的开始和结束而不需要额外的操作。 - Arnas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接