UINavigationController推送转换期间的低帧速率

时间:2010-11-29 18:48:26

标签: iphone ios uinavigationcontroller caanimation catransition

我有UINavigationController,并从根视图控制器推送到下一个视图控制器。第二个视图控制器相当“重”,因为它有很多初始化和子视图。

我的问题是:过渡动画执行得非常糟糕。基本上,动画的帧速率非常低(从“推”动画中我可能总共得到3-4帧。

我尝试了各种不同的技术,包括两种不同的方法来手动设置转换动画。在所有情况下,动画的前0.4-0.7秒都会受到这种不良帧率的影响。例如,如果我将转换设置为5秒,那么前半秒左右的效果很差,但动画的其余部分非常流畅。

这让我相信在转换开始时会发生“某事” - 这会导致设备以非常低的帧速率制作动画。

在我的代码中注入了很多NSLog语句后,我发现有两件事情发生了。首先,显然第二个视图在推送过程中是延迟加载的。我通过在执行推送之前访问view属性上的getter来修复此问题。我可以确认这会导致在推动动画开始之前发生所有初始化。

其次,我的应用程序大部分时间都会在转换过程中收到低内存警告。然而,即使在我没有得到记忆警告的情况下,动画仍然表现得很差 - 让我相信这些都不是原因。

我的问题:有没有其他人在UINavigationController推送过渡动画中遇到低帧率,但仅限于动画的前0.4到0.7秒?幕后是否还有其他事情会导致它,并且可以做任何事情吗?

作为参考,这是我当前加载并推送到下一个视图的代码。我有意访问视图getter,以强制视图在转换之前加载和初始化(主要是为了排除问题)。此代码使用performSelectorOnMainThread:::在主线程上执行,以响应Web服务回调。

PlayingFieldViewController *v = [[PlayingFieldViewController alloc] initWithNibName:@"PlayingFieldView" bundle:[NSBundle mainBundle]];
UIView *lazy = v.view;
[appDelegate.navigationController pushViewController:v animated:YES];
[v release];

我还尝试了一些其他动画技术,结果相同:

CATransition *transition = [CATransition animation];
transition.duration = 1.0;
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromRight;
[appDelegate.navigationController.view.layer addAnimation:transition forKey:kCATransition];
[appDelegate.navigationController pushViewController:v animated:NO];

[UIView 
  transitionWithView:appDelegate.navigationController.view
  duration:1.0
  options:UIViewAnimationOptionTransitionCurlUp
  animations:^{
   [appDelegate.navigationController pushViewController:v animated:NO];
  }
  completion:NULL];

2 个答案:

答案 0 :(得分:4)

经过进一步测试,我能够诊断出问题。涉及的第二个视图包括许多UIImageViews。删除这些视图或隐藏它们可以解决问题。

让我失望的是,只有动画的第一部分遭受帧速率问题,而动画的其余部分非常流畅(在动画较长的情况下)。这告诉我,即使所有子视图都存在,该设备也能够平滑地动画过渡动画。

我仍然不是iOS合成的专家,但我猜测各个层正在布局和缓存,导致速度减慢。解决方法是在隐藏大部分子视图的情况下推送到视图,然后在视图可见后使用另一个动画显示它们。

答案 1 :(得分:0)

我没有使用导航控制器偶然发现这一点,但是当从另一个线程更新表视图时我得到了相同的结果,首先更新了UI但是在短暂的延迟之后,所有内容都再次显示。正如Justin在评论中指出的那样,你应该在主线程上做UI工作。完成此操作的一种简单方法是将您的调用包装到GCD块中的UI:

dispatch_sync(dispatch_get_main_queue(), ^{
// Do UI stuff here
});

或使用

performSelectorOnMainThread:withObject:waitUntilDone: