iOS
Swift
playground
Swift3.0
Xcode8

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

More than 1 year has passed since last update.

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

第1回:【初心者向け】Swift3で爆速コーディングその1(画面作成とSnippetsの使い方)
第2回:【初心者向け】Swift3で爆速コーディングその2(UIViewと文字表示)
第3回:【初心者向け】Swift3で爆速コーディングその3(ボタンクリックとイベント)

画像の読み込み

今回使う画像です。cat.png
cat.png

左ペインを開きます。
スクリーンショット 2016-09-25 12.20.32.png

Resourceグループを右クリックしてcat.png画像を追加します
スクリーンショット 2016-09-25 12.17.58.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

プレビュー

猫の画像がアニメーションします。
スクリーンショット 2016-09-25 13.38.50.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("アニメーション終了")          
}