CAAnimationで色をアニメーションできないケース(iOS)

# はじめに
CATextLayerをCABasicAnimationを用いてテキストの色を変えていたのですが、テキストの色が変わらないケースがあり、バグが生じていました。
今回はCABasicAnimationを用いたテキストの色を変化させるアニメーションのバグとその解決策について述べていきたいと思います。

***今回の要点***

- 元々の色と、アニメーションで変化させる色が同じだとアニメーションしない
- CABasicAnimationの`removedOnCompletion`プロパティを意識する
- 画面遷移時にアニメーションを終了させる

なお、UILabelやUIButtonなどのテキストをアニメーションさせる方法については[UIButtonやUILabelなどのテキストにアニメーションをつける](http://qiita.com/shoheiyokoyama/items/2fc9df01cfd5eb6429f9)に詳しく記述してあるので参考にどうぞ

## 議論

CABasicAnimationを用いてCATextLayerのテキストの色を変えるアニメーションができなくなるケースが発生する

## 今回のケース

今回は、永続的にCATextLayerのテキストの色を変化させる実装をしていました。
画面遷移から戻ってきた後もアニメーションを継続させるため、viewDidAppearでアニメーションさせています。コードは以下になります。

前提条件として、textLayerの文字色は
`self.textLayer.foregroundColor = UIColor.blackColor().CGColor`
に設定されています

```swift:Swift
    func animateTextColor() {
        var textColorAnimation = CABasicAnimation(keyPath: "foregroundColor")
        textColorAnimation.duration = 2.0

        //永続的にテキストカラーを変え続ける
        textColorAnimation.autoreverses = true
        textColorAnimation.repeatCount = 1e100

        textColorAnimation.fromValue = UIColor.clearColor().CGColor
        textColorAnimation.toValue = UIColor.redColor().CGColor
        self.textLayer.foregroundColor = UIColor.redColor().CGColor
        self.textLayer.addAnimation(textColorAnimation, forKey: "TextColor")
    }

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

        animateTextColor()
    }
```

```objc:Objective-C
- (void)animateTextColor {
    CABasicAnimation *textColorAnimation = [CABasicAnimation animationWithKeyPath:@"foregroundColor"];
    textColorAnimation.duration = 2.0;
    
    textColorAnimation.autoreverses = true;
    textColorAnimation.repeatCount = 1e100;
    
    textColorAnimation.fromValue = (__bridge id _Nullable)([UIColor clearColor].CGColor);
    textColorAnimation.toValue = (__bridge id _Nullable)([UIColor redColor].CGColor);
    self.textLayer.foregroundColor = (__bridge id _Nullable)([UIColor redColor].CGColor);
    
    [self.textLayer addAnimation:textColorAnimation forKey:@"TextColor"];
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    
    [self animateTextColor];
}
```

この場合、画面遷移から戻ってきた後では、`animateTextColor`が呼び出されてもテキストのアニメーションが止まってしまうようです。

![mov.gif](https://qiita-image-store.s3.amazonaws.com/0/62451/29aebc63-04ea-87ce-7bb1-9774ff53c57c.gif)

## 解決策

以下は画面遷移して戻ってきた後でも、アニメーションが正常に動くようにする方法です。

### 1. viewDidAppearのタイミングでアニメーションを取り消す

```swift:Swift
    override func viewDidDisappear(animated: Bool) {
        super.viewDidDisappear(animated)

        self.textLayer.removeAllAnimations()
        self.textLayer.foregroundColor = self.blackColor().CGColor
    }
```

```objc:Objective-C
- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear];
    
    [self.textLayer removeAllAnimations];
    self.textLayer.foregroundColor = (__bridge id _Nullable)([UIColor blackColor].CGColor);
}
```

画面が切り替わる`viewDidDisappear`のタイミングで一回アニメーションを取り消せば、解決できました。

しかし、`removeAllAnimations`を呼び出さなくても`transform.scale`や`borderWidth`など***他のアニメーションは動く***ようです。

### 2. removedOnCompletionのプロパティをoffにする
```swift:Swift
   textColorAnimation.removedOnCompletion = false
```
```objc:Objective-C
   textColorAnimation.removedOnCompletion = NO;
```

`removedOnCompletion`のプロパティをoffにすることでこの問題は解決できました。
画面遷移から戻ってきた後も、CAAnimationによってテキストの色が変わっています。

![mo2.gif](https://qiita-image-store.s3.amazonaws.com/0/62451/6d040ab8-827b-2a73-c28c-273f9c007484.gif)

## 今回のケースわかったこと

一回画面遷移して戻ってきた後に`removedOnCompletion`がonの状態(default)ではアニメーションはされなくなっていましたが、この時`textLayer`の`foregroundColor`の値は、`textColorAnimation`の`toValue`の値に変わっていました。
アニメーションが終わってない状況で画面遷移したので`textColorAnimation`が消去されなくそのままの状態で止まっていたようですね。

次は初期状態で
`self.textLayer.foregroundColor = UIColor.whiteColor().CGColor`
に設定し、`animateTextColor()`を呼び出したところ...
***「アニメーションがされない」***

今回のバグから気づいたのですが、***変化させたい部分の元々の色とCAAnimationによって変化させる色が等しい場合は、色が変化するアニメーションはされない***のですね。

つまり今回のケースは、`textLayer`の`foregroundColor`の色と`textColorAnimation`の`toValue`の色が同じになってしまったため、`animateTextColor()`を呼び出してもアニメーションがされなくなってしまったんですね。

# 最後に
今回は、CAAnimationを用いたアニメーションで色が変化しないケースとその解決法を紹介しました。
CAAnimationはUXに密接に関わってくる部分なので、アプリケーションに組み込むとクオリティも変わってくると思います。