【初心者向け】Swift3で爆速コーディングその４(画像とアニメーション)


Playgroundによるコーディングです。
初めての方は下記をご参考ください。

第１回：[【初心者向け】Swift3で爆速コーディングその１(画面作成とSnippetsの使い方)](http://qiita.com/teradonburi/items/d0ffb6367e34966d761b)
第２回：[【初心者向け】Swift3で爆速コーディングその２(UIViewと文字表示)](http://qiita.com/teradonburi/items/fe79959d692c7efc99d1)
第３回：[【初心者向け】Swift3で爆速コーディングその３(ボタンクリックとイベント)](http://qiita.com/teradonburi/items/381aabdf547977953d48#_reference-4e99e4f5de9c0f6c2d05)

# 画像の読み込み
今回使う画像です。cat.png
![cat.png](https://qiita-image-store.s3.amazonaws.com/0/55077/3ff18c6d-f34b-6e0f-721b-767b4d48b77f.png)


左ペインを開きます。
![スクリーンショット 2016-09-25 12.20.32.png](https://qiita-image-store.s3.amazonaws.com/0/55077/4e7b8e4a-5a4d-314b-35ac-2961eb6455a6.png)


Resourceグループを右クリックしてcat.png画像を追加します
<img width="368" alt="スクリーンショット 2016-09-25 12.17.58.png" src="https://qiita-image-store.s3.amazonaws.com/0/55077/a8147343-08d0-955b-5e60-11bbb758605f.png">

追加後、UIImageクラスでロードし、UIImageViewで画像が表示できます。

```
// 画像を表示する
let img: UIImage = UIImage(named: "cat.png")!
let imgView: UIImageView = UIImageView(frame:  CGRect(x: 0, y: 30, width: 80, height: 80))
imgView.image = img
self.view.addSubview(imgView)
```

# ソースコード

今回の全ソースコードです。

```

import UIKit
import CoreImage


class ViewController: UIViewController {
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        
        // 画像を設定する
        var img: UIImage = UIImage(named: "cat.png")!
        
        // セピア(フィルター処理)
        let sepiaFilter = CIFilter(name: "CISepiaTone")
        sepiaFilter?.setValue(CIImage(image:img), forKey: kCIInputImageKey)
        sepiaFilter?.setValue(0.8, forKey: kCIInputIntensityKey)
        // UIImageに変換
        img = UIImage(ciImage: sepiaFilter!.outputImage!)
        
        
        let imgView: UIImageView = UIImageView(frame:  CGRect(x: 0, y: 30, width: 80, height: 80))
        imgView.image = img
        
        
        // スケール行列を生成する
        let transformScale:CGAffineTransform = CGAffineTransform(scaleX: 0.75, y: 0.75)
        // 回転行列を生成する
        let transformRot:CGAffineTransform = CGAffineTransform(rotationAngle: CGFloat((30.0 * M_PI) / 180.0))
        // 平行移動行列を生成する
        let transformTrans:CGAffineTransform = CGAffineTransform(translationX: 100, y: 0);
        
        // 単位行列を生成する
        var transform:CGAffineTransform = CGAffineTransform.identity
        // スケーリング行列×回転行列×平行移動行列＝縮小して回転して平行移動
        transform = transformScale.concatenating(transformRot);
        transform = transform.concatenating(transformTrans);
        // 逆順だと結果が変わるので注意
        // 平行移動する前の位置を起点に回転してしまう
        //transform = transformTrans.concatenating(transformRot);
        //transform = transform.concatenating(transformScale);
        
        imgView.transform = transform
        
        
        
        self.view.addSubview(imgView)
        
        
        
        UIView.animate(
            // アニメーションの時間（秒）
            withDuration: 1.0,
            // 遅延時間
            delay: 3.0,
            // バネ係数
            usingSpringWithDamping: 1,
            
            // 初速度
            initialSpringVelocity: 1.0,
            
            // 一定の速度
            options: UIViewAnimationOptions.curveLinear,
            
            animations: { () -> Void in
                // スケール行列を生成する
                let transformScale:CGAffineTransform = CGAffineTransform(scaleX: 0.5, y: 0.5)
                // 回転行列を生成する
                let transformRot:CGAffineTransform = CGAffineTransform(rotationAngle: CGFloat((45.0 * M_PI) / 180.0))
                // 平行移動行列を生成する
                let transformTrans:CGAffineTransform = CGAffineTransform(translationX: 200, y: 0);
                
                // 単位行列を生成する
                var transform:CGAffineTransform = CGAffineTransform.identity
                // スケーリング行列×回転行列×平行移動行列＝縮小して回転して平行移動
                transform = transformScale.concatenating(transformRot);
                transform = transform.concatenating(transformTrans);
                
                
                imgView.transform = transform
                
            // アニメーション完了時の処理
            }) { (Bool) -> Void in
            print("アニメーション終了")                      
        }
        
    print(self.view.perform(Selector(("recursiveDescription"))))

    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
}

let window = UIWindow(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
let viewController = ViewController()
viewController.view.backgroundColor = UIColor.white

window.rootViewController = viewController
window.makeKeyAndVisible()

import PlaygroundSupport

PlaygroundPage.current.liveView = window
PlaygroundPage.current.needsIndefiniteExecution = true
```

# プレビュー

猫の画像がアニメーションします。
<img width="1166" alt="スクリーンショット 2016-09-25 13.38.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/55077/ef655f9d-18fa-d648-96cd-8cfa532fcf9b.png">


# 画像にフィルターをかける
画像処理をするにはCoreImageフレームワークを利用します。

```
import CoreImage
```

今回は次の行でセピアフィルタをかけています。
画像処理をするためにはCIImageクラスに変換して
画像処理後UIImageクラスに変換し直しています。

```
// セピア(フィルター処理)
let sepiaFilter = CIFilter(name: "CISepiaTone")
sepiaFilter?.setValue(CIImage(image:img), forKey: kCIInputImageKey)
// フィルタの強さ、かける割合
sepiaFilter?.setValue(0.8, forKey: kCIInputIntensityKey)
// UIImageに変換
img = UIImage(ciImage: sepiaFilter!.outputImage!)
```

# 画像の姿勢（スケール、向き、位置）
CGAffineTransformクラスを使うことで
UIViewの姿勢を指定することができます。
CGAffineTransformクラスは行列による変換を行います。
スケール、向き、位置の行列を生成し、
concatenatingメソッドで行列の掛け算を行っています。
行列による計算なのでかける順番を間違えると結果が変わってしまうことに注意です。
普通はスケーリング行列×回転行列×平行移動行列の順番に掛け算します。

```
// スケール行列を生成する
let transformScale:CGAffineTransform = CGAffineTransform(scaleX: 0.75, y: 0.75)
// 回転行列を生成する
let transformRot:CGAffineTransform = CGAffineTransform(rotationAngle: CGFloat((30.0 * M_PI) / 180.0))
// 平行移動行列を生成する
let transformTrans:CGAffineTransform = CGAffineTransform(translationX: 100, y: 0);
        
// 単位行列を生成する
var transform:CGAffineTransform = CGAffineTransform.identity
// スケーリング行列×回転行列×平行移動行列＝縮小して回転して平行移動
transform = transformScale.concatenating(transformRot);
transform = transform.concatenating(transformTrans);
// 逆順だと結果が変わるので注意
// 平行移動する前の位置を起点に回転してしまう
//transform = transformTrans.concatenating(transformRot);
//transform = transform.concatenating(transformScale);
        
imgView.transform = transform

```

# 画像のアニメーション

UIView.animateメソッドによりTweenアニメーションを行っています。
withDurationはアニメーションの時間です。
delayはアニメーション開始までの時間です。
usingSpringWithDampingはバネ係数です。値が小さいほど跳ね返りが強くなります。0.2などの値を入れると跳ねるような動きになるはずです。
initialSpringVelocityはアニメーションの初速度です。
optionsにはアニメーションの速度変化を入れます。UIViewAnimationOptionsクラスのパラメータで指定します。

* curveLinear:一定速度
* curveEaseIn:動き始めがゆっくり
* curveEaseOut:動き終わりがゆっくり
* curveEaseInOut:動き始めと終わりがゆっくり

animationメソッドにはアニメーション完了後の姿勢を定義します。
始めと終わりの姿勢に対し、補間されてアニメーションされます。

```
UIView.animate(
            // アニメーションの時間（秒）
            withDuration: 1.0,
            // 遅延時間
            delay: 3.0,
            // バネ係数
            usingSpringWithDamping: 1,
            
            // 初速度
            initialSpringVelocity: 1.0,
            
            // 一定の速度
            options: UIViewAnimationOptions.curveLinear,
            
            animations: { () -> Void in

           　　    // アニメーション完了時の姿勢を定義すると補間される     
            }
// アニメーション完了時の処理
) { (Bool) -> Void in
  print("アニメーション終了")          
}
```