如何为UINavigationBar setBackgroundImage: forBarMetrics:添加动画效果?

9

当某个控制器被推送时,我正在更改导航栏的背景图像。我想要动画效果。我可以使用以下代码实现:

[UIView transitionWithView:self.navigationController.navigationBar
                  duration:0.3f
                   options:UIViewAnimationOptionTransitionCrossDissolve
                animations:^{
    [self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"now-playing-nav-bar.png"]
                                                 forBarMetrics:UIBarMetricsDefault];
} completion:NULL];

然而,这会阻止应用于navigationBarTitle和UIBarButtonItem的默认推送动画。我该如何使背景更改和推送动画一起工作?我希望尽可能使用原始解决方案。附注:我不能使用tintColor,因为背景是纹理的。

如果在新的视图控制器的viewWillAppear:中设置backgroundImage会发生什么? - Benjamin Mayo
@BenjaminMayo 转场动画正常工作,但推送动画不起作用。 - duci9y
摆脱转换块,只需更改背景图片。这有帮助吗? - Benjamin Mayo
@BenjaminMayo 这并不会使背景图片动画化,它只是出现了。 - duci9y
@BenjaminMayo 我找到了解决方案。 - duci9y
3个回答

26

仅在iOS 6上进行过测试

我使用核心动画解决了这个问题:

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

    CATransition *animation = [CATransition animation];
    animation.duration = 0.3;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    animation.type = kCATransitionFade;

    [self.navigationController.navigationBar.layer addAnimation:animation forKey:nil];

    [UIView animateWithDuration:0.3 animations:^{
        [self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"now-playing-nav-bar.png"] forBarMetrics:UIBarMetricsDefault];
    }];
}

viewWillDisappear:中做同样的操作,然后你就可以开始了。


@RudolfAdamkovic 这是一个旧回答,当时我还是个初学者。我甚至没有使用块动画。很快就会更新它。谢谢提醒。 :) - duci9y
@RudolfAdamkovic 已更新。 - duci9y
1
刚在iOS7和iOS8上测试了代码,代码可以正常运行,并且交互式弹出窗口也可以自动工作,太棒了!然而,UIView动画API是不必要的。 - axl411
@zannnennkunn 很好!如果您能编辑答案并包含可用的版本,我将不胜感激。 - duci9y
1
@duci9y 编辑。这里有一个代码注意事项,我还没有去研究 (UIPercentDrivenInteractiveTransition 可能是正确的查看位置):开始一个交互式弹出窗口,然后取消弹出窗口,然后导航栏将首先在 viewWillDisappear 中执行动画,然后在 viewWillAppear 中执行动画。除此之外,该代码可以很好地处理推送、弹出和交互式弹出 (只要不取消弹出)。感谢您的回答。 - axl411
显示剩余3条评论

5

这在iOS 9上适用:

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)

    changeNavigationBackground()
}

func changeNavigationBackground() {
    // navigationBar should always exist if the view controller is in a UINavigationController
    guard let navigationBar = navigationController?.navigationBar else { return }

    // the current navigation background
    guard let imageView = navigationBar.subviews.filter({ $0 is UIImageView }).first else { return }
    let image = UIImage(named: "navigation_background")
    let newImageView = UIImageView(image: image)
    newImageView.frame = imageView.frame
    newImageView.alpha = 0.0
    navigationBar.insertSubview(newImageView, belowSubview: imageView)

    transitionCoordinator()?.animateAlongsideTransition({ (context) in
        imageView.alpha = 0.0
        newImageView.alpha = 1.0
    }, completion: { (context) in
        newImageView.removeFromSuperview()
        navigationBar.setBackgroundImage(image, forBarMetrics: .Default)
        imageView.alpha = 1.0
    })
}

如果可能的话,我会避免使用核心动画,因此我只使用视图并在过渡时更改它们的透明度值。


0

如果没有转场动画,推送动画是否有效?如果是,则可能需要在更改导航栏图像的块中自己执行推送动画。


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