UIView.animateで色が上手くフェードアニメーションして変わらない部品たち

# はじめに
こんにちは。
色をフェードアニメーションして変更する時に少し悩んだので書いてみました。
簡単なアニメーションをする場合、以下のようなメソッドを利用すると思います。

```swift
UIView.animate(withDuration: 0.5, delay: 0, animations: { [unowned self] Void in
    //処理
})
```

![sample.gif](https://qiita-image-store.s3.amazonaws.com/0/128250/fe2b6a4e-d00e-043f-cdc8-f99b6dac8efb.gif)

アプリ制作にあたり、UIButtonやUISwitch,UINavigationBarなどの
**backgroundColor**や**tintColor**をアニメーションをしながら変更したいと思ったのですが、一部の部品で正常にフェードアニメーションをせず、すぐに色が変わってしまうことがあったので少し調べてみました。
至らぬ点など多々あると思いますが、コメントなど頂けたら幸いです。

# UI部品一覧(主に変更するプロパティを書いてみました)
|部品名|正常にフェードアニメーションする|正常にフェードアニメーションしない|
|:-:|:-:|:-:|
|UINavigationBar|-|barTintColor,※titleTextColor|
|UIView|backgroundColor|-|
|UIButton|backgroundColor,tintColor|-|
|UISwitch|backgroundColor|onTintColor|
|UILabel|-|backgroundColor,textColor|
|UISegmentedControl|tintColor|-|

# 解決するためのExtensionを書いてみる
**正常にアニメーションしない**プロパティに対してExtensionで対応してみたいと思います。
関数名などは、ご自由に変更してください。

## UINavigationBar
※**titleTextColor**という計算型プロパティを追加しています※

```swift
extension UINavigationBar {
    func setBarTintColor(_ color: UIColor, duration: TimeInterval = 0, option: UIViewAnimationOptions = [], completion:(()->())? = nil) {
        var setting: UIViewAnimationOptions = option
        setting.insert(UIViewAnimationOptions.transitionCrossDissolve)
        UIView.transition(with: self, duration: duration, options: setting, animations: {
            self.barTintColor = color
        }) { (finish) in
            if finish { completion?() }
        }
    }
    
    func setTitleTextColor(_ color: UIColor, duration: TimeInterval = 0, option: UIViewAnimationOptions = [], completion:(()->())? = nil) {
        var setting: UIViewAnimationOptions = option
        setting.insert(UIViewAnimationOptions.transitionCrossDissolve)
        UIView.transition(with: self, duration: duration, options: setting, animations: {
            self.titleTextColor = color
        }) { (finish) in
            if finish { completion?() }
        }
    }
    
    //バーのタイトルの文字の色を変更できます
    var titleTextColor: UIColor {
        get {
            let color = titleTextAttributes?[NSForegroundColorAttributeName] as! UIColor
            return color
        }
        set {
            titleTextAttributes = [NSForegroundColorAttributeName : newValue]
        }
    }
}
```

## UISwitch

```swift
extension UISwitch {
    func setOnTintColor(_ color: UIColor, duration: TimeInterval = 0, option: UIViewAnimationOptions = [], completion:(()->())? = nil) {
        var setting: UIViewAnimationOptions = option
        setting.insert(UIViewAnimationOptions.transitionCrossDissolve)
        if !isOn {
            self.onTintColor = color
            return
        }
        UIView.transition(with: self, duration: duration, options: setting, animations: {
            self.onTintColor = color
        }) { (finish) in
            if finish { completion?() }
        }
    }
}
```

## UILabel

```swift
extension UILabel {
    func setBackgroundColor(_ color: UIColor, duration: TimeInterval = 0, option: UIViewAnimationOptions = [], completion:(()->())? = nil) {
        var setting: UIViewAnimationOptions = option
        setting.insert(UIViewAnimationOptions.transitionCrossDissolve)
        UIView.transition(with: self, duration: duration, options: setting, animations: {
            self.backgroundColor = color
        }) { (finish) in
            if finish { completion?() }
        }
    }
    
    func setTextColor(_ color: UIColor, duration: TimeInterval = 0, option: UIViewAnimationOptions = [], completion:(()->())? = nil) {
        var setting: UIViewAnimationOptions = option
        setting.insert(UIViewAnimationOptions.transitionCrossDissolve)
        UIView.transition(with: self, duration: duration, options: setting, animations: {
            self.textColor = color
        }) { (finish) in
            if finish { completion?() }
        }
    }
}
```

# サンプルコード
無事にアニメーションをしてくれたようです。

![ok.gif](https://qiita-image-store.s3.amazonaws.com/0/128250/a3e1ba6a-517c-8ee9-99a1-de3161291d47.gif)

```swift
import UIKit

class MainViewController: UIViewController {
    
    @IBOutlet weak var navigationBar: UINavigationBar!
    @IBOutlet weak var uiView: UIView!
    @IBOutlet weak var button: UIButton!
    @IBOutlet weak var uiSwitch: UISwitch!
    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var segmentedControl: UISegmentedControl!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    @IBAction func blueAction(_ sender: Any) {
        let color = UIColor(hex: 0xbce7fe)
        UIView.animate(withDuration: 0.5, delay: 0, animations: { [unowned self] Void in
//            self.navigationBar.barTintColor = color
            self.uiView.backgroundColor = color
            self.button.backgroundColor = color
//            self.uiSwitch.onTintColor = color
//            self.label.backgroundColor = color
            self.segmentedControl.tintColor = color
        })
        navigationBar.setBarTintColor(color, duration: 0.5)
        uiSwitch.setOnTintColor(color, duration: 0.5)
        label.setBackgroundColor(color, duration: 0.5)
    }
    
    @IBAction func greenAction(_ sender: Any) {
        let color = UIColor(hex: 0xa7e040)
        UIView.animate(withDuration: 0.5, delay: 0, animations: { [unowned self] Void in
//            self.navigationBar.barTintColor = color
            self.uiView.backgroundColor = color
            self.button.backgroundColor = color
//            self.uiSwitch.onTintColor = color
//            self.label.backgroundColor = color
            self.segmentedControl.tintColor = color
        })
        navigationBar.setBarTintColor(color, duration: 0.5)
        uiSwitch.setOnTintColor(color, duration: 0.5)
        label.setBackgroundColor(color, duration: 0.5)
    }
}
```

# 参考にさせていただいた記事
iOSアニメーションについて
> [iOSのアニメーションあれこれ(Objective-C/Swift(※随時更新中)) Qiita](http://qiita.com/masuhara/items/5513eedc4ca0eda656b7)

UIView animateについて
> [Apple API Reference UIView](https://developer.apple.com/reference/uikit/uiview)

見て頂いてありがとうございます。