LoginSignup
27
17

More than 5 years have passed since last update.

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

Posted at

はじめに

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

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

sample.gif

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

UI部品一覧(主に変更するプロパティを書いてみました)

部品名 正常にフェードアニメーションする 正常にフェードアニメーションしない
UINavigationBar - barTintColor,※titleTextColor
UIView backgroundColor -
UIButton backgroundColor,tintColor -
UISwitch backgroundColor onTintColor
UILabel - backgroundColor,textColor
UISegmentedControl tintColor -

解決するためのExtensionを書いてみる

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

UINavigationBar

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

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

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

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

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

UIView animateについて

Apple API Reference UIView

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

27
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
17