我在导航控制器中嵌入了一个控制器。假设我有一个按钮,可以稍微重新定位self.navigationController.navigationBar。然后,我使用任何控制器执行presentViewControllerAnimated(无论是否导航),并将其关闭后,导航栏返回其原始位置(实际上,在关闭动画开始时它处于其原始位置)。在iOS 6及更低版本中,该栏不会自动重新定位。知道如何防止在iOS 7中重新定位吗?

最佳答案

好的,所以我终于正确了。

首先-Apple不希望我们更改UINavigationBar的位置。因此,您应该不惜一切代价避免它。以我为例,我有一个应用程序要修复,该应用程序移动了UINavigationBar以显示滑出菜单。滑出菜单问题的正确解决方案是将UINavigationController放进内部-然后您可以将整个UINavigationController连同其内容(无论它是什么)一起滑动,一切正常。由于某种原因,UINavigationController不在此应用程序中。因此,我不得不求助于黑客。如果可以选择不使用此方法,请不要使用此方法。这是一个hack,可能会在进一步的iOS版本中中断,Apple肯定不会喜欢它。

首先,探索iOS7中的新过渡系统:http://www.doubleencore.com/2013/09/ios-7-custom-transitions/

然后,替换:

[self presentViewController:navigationController animated:YES completion:nil];




if([UIApplication iOS7]) /* or any other custom iOS7 detection method you implement */
{ /* we simulate old transition with nav bar slided out */
  navigationController.transitioningDelegate = [OMModalTransitionDelegate new];
}

[self presentViewController:navigationController animated:YES completion:nil];


因此,我们需要一个过渡委托来模拟标准行为并完成技巧。

#import "OMModalTransitionDelegate.h"
#import "OMAnimatedTransitioning.h"

@implementation OMModalTransitionDelegate

- (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
{
  OMAnimatedTransitioning *transitioning = [OMAnimatedTransitioning new];
  return transitioning;
}

- (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
{
  OMAnimatedTransitioning *transitioning = [OMAnimatedTransitioning new];
  transitioning.reverse = YES;
  return transitioning;
}

@end


现在是实际的动画管理器(您必须自己在UINavigationBar的类别中实现sharedBar):

static NSTimeInterval const DEAnimatedTransitionDuration = 0.4f;
static NSTimeInterval const DEAnimatedTransitionMarcoDuration = 0.15f;


@implementation OMAnimatedTransitioning


- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
  UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
  UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
  UIView *container = [transitionContext containerView];
  UIView *superView = [UINavigationBar sharedBar].superview;
  CGRect barFrame = [UINavigationBar sharedBar].frame;
  if(self.reverse)
  { /* Trick - first, remove the bar from it's superview before animation starts */
    [[UINavigationBar sharedBar] removeFromSuperview];
  }
  CGRect oldFrame = container.bounds;
  if (self.reverse)
  {
    [container insertSubview:toViewController.view belowSubview:fromViewController.view];
  }
  else
  {
    toViewController.view.frame = oldFrame;
    toViewController.view.transform = CGAffineTransformMakeTranslation(0, CGRectGetHeight(oldFrame));
    [container addSubview:toViewController.view];
  }

[UIView animateKeyframesWithDuration:DEAnimatedTransitionDuration delay:0 options:0 animations:^
{
  if (self.reverse)
  {
    fromViewController.view.transform = CGAffineTransformMakeTranslation(0, CGRectGetHeight(oldFrame));
    double delayInSeconds = 0.01; /* Trick - after an imperceivable delay - add it back - now it is immune to whatever Apple put there to move it */
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void)
    {
        [UINavigationBar sharedBar].frame = barFrame;
        [superView addSubview:[UINavigationBar sharedBar]];
    });

  }
  else
  {
    toViewController.view.transform = CGAffineTransformIdentity;
  }
} completion:^(BOOL finished) {


  [transitionContext completeTransition:finished];
}];
}

- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
  return DEAnimatedTransitionDuration;
}
@end

10-08 06:04