iOS10中导航栏barTintColor变化的动画效果无法实现

12

我升级到了XCode 8.0 / iOS 10,现在我的导航栏颜色变化动画不再起作用,它直接改变颜色而没有任何动画效果。

UIView.animateWithDuration(0.2, animations: {
    self.navigationController?.navigationBar.barTintColor = currentSection.color!
})

有人知道如何修复这个问题吗?

2个回答

38
在iOS10中,要使navigationBar的颜色变化动画化,您需要在动画块中设置颜色后调用layoutIfNeeded
示例代码:
UIView.animateWithDuration(0.5) { 
    self.navigationController?.navigationBar.barTintColor = UIColor.redColor()
    self.navigationController?.navigationBar.layoutIfNeeded()
}

我想提醒一下,苹果官方不支持在barTintColor等属性中使用动画效果,因此该方法可能随时会出现问题。

如果在动画块中调用-layoutIfNeeded来更新导航栏的背景属性,则应该可以更新,但考虑到这些属性的性质,实际上从来没有任何保证可以对它们进行任何动画处理。


确实可以工作,但我的导航栏标题也在动画(我没有在“animateWithDuration”函数中设置标题)。当颜色变化正在进行动画时,标题从左上角移动到导航栏的中心... - Tiois
@Tiois,我认为这个问题只存在于你的项目中。可能是你在同一布局周期中设置了标题,请检查你在ViewController中更改的所有属性。我已经创建了一个测试项目,标题保持不变,你可以在这里检查它:https://dl.dropboxusercontent.com/u/42855950/test.zip - Vasily
你是对的,设置标题后,我现在在导航上调用layoutIfNeeded(),然后调用UIView.animateWithDuration函数与layoutIfNeeded()一起使用,一切都正常!谢谢。 - Tiois
你刚刚拯救了我的一天。 - Sazzad Hissain Khan
1
layoutIfNeeded() 的效果非常棒,感谢你挽救了这一天。 :) - Yash Bedi

4

交互式动画

Interactive animation

定义一个协议:

/// Navigation bar colors for `ColorableNavigationController`, called on `push` & `pop` actions
public protocol NavigationBarColorable: UIViewController {
    var navigationTintColor: UIColor? { get }
    var navigationBarTintColor: UIColor? { get }
}

public extension NavigationBarColorable {
    var navigationTintColor: UIColor? { return nil }
}

定义一个自定义的NavigationController的子类:

class AppNavigationController: UINavigationController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        navigationBar.shadowImage = UIImage()
        if let colors = rootViewController as? NavigationBarColorable {
            setNavigationBarColors(colors)            
        }
    }
    
    private var previousViewController: UIViewController? {
        guard viewControllers.count > 1 else {
            return nil
        }
        return viewControllers[viewControllers.count - 2]
    }
    
    override open func pushViewController(_ viewController: UIViewController, animated: Bool) {
        if let colors = viewController as? NavigationBarColorable {
            setNavigationBarColors(colors)
        }
               
        super.pushViewController(viewController, animated: animated)
    }
    
    override open func popViewController(animated: Bool) -> UIViewController? {
        if let colors = previousViewController as? NavigationBarColorable {
            setNavigationBarColors(colors)
        }
                        
        // Let's start pop action or we can't get transitionCoordinator()
        let popViewController = super.popViewController(animated: animated)
        
        // Secure situation if user cancelled transition
        transitionCoordinator?.animate(alongsideTransition: nil, completion: { [weak self] context in
            guard let `self` = self else { return }

            guard let colors = self.topViewController as? NavigationBarColorable else { return }
            self.setNavigationBarColors(colors)
        })
        
        return popViewController
    }
    
    override func popToRootViewController(animated: Bool) -> [UIViewController]? {
        if let colors = rootViewController as? NavigationBarColorable {
            setNavigationBarColors(colors)
        }
        
        let controllers = super.popToRootViewController(animated: animated)
        
        return controllers
    }
    
    private func setNavigationBarColors(_ colors: NavigationBarColorable) {
        
        if let tintColor = colors.navigationTintColor {
            navigationBar.titleTextAttributes = [
                .foregroundColor : tintColor
            ]
            navigationBar.tintColor = tintColor
        }
        
        navigationBar.barTintColor = colors.navigationBarTintColor
    }
}

现在你可以在AppNavigationController中的任何控制器中实现NavigationBarColorable,并设置任何你想要的颜色。
extension FirstViewController: NavigationBarColorable {
    public var navigationBarTintColor: UIColor? { UIColor.red }
    public var navigationTintColor: UIColor? { UIColor.white }
}

extension SecondViewController: NavigationBarColorable {
    public var navigationBarTintColor: UIColor? { UIColor.blue }
    public var navigationTintColor: UIColor? { UIColor.orange }
}

别忘了实现这个有用的扩展:

extension UINavigationController {
    var rootViewController: UIViewController? {
        return viewControllers.first
    }
}

有史以来最好的答案!谢谢。 - Emmett

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