カテゴリー
SugiBlog Webエンジニアのためのお役立ちTips

UIViewのアニメーション

この記事は最終更新日から1年以上経過しています。

今回はUIViewやUIButtonをアニメーションさせる方法をご紹介します。

まずはアニメーションさせる適当なViewを作成します。

let sampleView = UIView()

sampleView.frame.size = CGSize(width: 120, height: 120)
sampleView.center = CGPoint(x: 60, y: 60)
sampleView.backgroundColor = UIColor.white
sampleView.layer.borderColor = UIColor.cyan.cgColor
sampleView.layer.borderWidth = 2

view.addSubview(sampleView)

作成したViewをアニメーションさせるにはUIView.animateメソッドを使用します。
ここでは大きさを変更してみましょう。
中心点も設定しているのは、大きさを変更すると左上を起点に大きさが変わってしまうためです。

UIView.animate(withDuration: 0.5, animations: {
    self.sampleView.frame.size = CGSize(width: 80, height: 80)
    self.sampleView.center = CGPoint(x: 60, y: 60)
}, completion: { Void in
    // アニメーション完了時の処理を記述します
})

次に、大きさと角丸の半径をアニメーションで変更してみたいと思います。
サンプルとして、標準カメラアプリの動画撮影ボタンのようなボタンを作成してみましょう。
実際の撮影処理はしていません。

まずは必要な宣言

let shutterView = UIView()
let shutterButton = UIButton()
var isRecording: Bool = false

Viewを作成するメソッドを作成します。

func makeShutterView() {
    shutterView.frame.size = CGSize(width: 74, height: 74)
    shutterView.center = CGPoint(x: 45, y: 45)

    let shutterCircle = UIView()
    shutterCircle.frame.size = CGSize(width: 76, height: 76)
    shutterCircle.center = CGPoint(x: 45, y: 45)
    shutterCircle.layer.borderColor = UIColor.white.cgColor
    shutterCircle.layer.borderWidth = 4
    shutterCircle.layer.cornerRadius = 38.0
    shutterView.addSubview(shutterCircle)

    shutterButton.frame.size = CGSize(width: 60, height: 60)
    shutterButton.center = CGPoint(x: 45, y: 45)
    shutterButton.backgroundColor = UIColor.red
    shutterButton.layer.cornerRadius = 30.0
    shutterButton.addTarget(self, action: #selector(onClickRecordingButton), for: .touchUpInside)
    shutterView.addSubview(shutterButton)

    view.addSubview(shutterView)
}


次にボタンを押した時に実行されるメソッドです。
isRecordingをフラグとして動画の撮影開始・停止を判別しています。

func onClickRecordingButton(sender: UIButton) {

    if isRecording {

        isRecording = false
        stopRecoding()

    } else {

        isRecording = true
        startRecording()

    }

}

撮影開始のメソッド
※アニメーションについて別の書き方をしていますが動作は同じです。

サイズを小さくして少し角の丸い停止ボタンに変形させます。

func startRecording() {

    UIView.beginAnimations(nil, context: nil)
    UIView.setAnimationDuration(0.2) // アニメーション時間

    shutterButton.frame.size = CGSize(width: 40, height: 40)
    shutterButton.center = CGPoint(x: 45, y: 45)

    // 角丸半径のアニメーション
    shutterButtonCRAnimation(layer: shutterButton.layer, corner: 8.0, duration: 0.2)

    UIView.commitAnimations()

}

撮影停止のメソッド
元のサイズ・形に戻します。

func stopRecoding() {

    UIView.beginAnimations(nil, context: nil)
    UIView.setAnimationDuration(0.3) // アニメーション時間

    shutterButton.frame.size = CGSize(width: 60, height: 60)
    shutterButton.center = CGPoint(x: 45, y: 45)

    // 角丸半径のアニメーション
    shutterButtonCRAnimation(layer: shutterButton.layer, corner: 30.0, duration: 0.3)

    UIView.commitAnimations()

}

アニメーションに遅延を発生さたい場合はUIView.setAnimationDelay(1.3)等とします。

お気づきかもしれませんが、shutterButton.layer.cornerRadiusについては別メソッドでアニメーションさせています。
これはUIView.animateでは角丸半径のアニメーションをさせることが出来ないからです。

UIView.animateでアニメーションさせることが出来るのは以下の通り。

frame ビューの位置とサイズ
bounds ビューのサイズ
center ビューの位置
transform ビューへの変形処理
alpha ビューの透過度
backgroundColor ビューの背景色
contentStretch ビュー上のコンテンツのストレッチ方法

UIView.animateでアニメーションさせることが出来ないものは、Core Animationでアニメーションさせる必要があります。
以下が角丸半径をアニメーションさせる方法になります。

func shutterButtonCRAnimation(layer: CALayer, radius: CGFloat, duration: CFTimeInterval) {
    let crAnimation = CABasicAnimation(keyPath: "cornerRadius")
    crAnimation.toValue = radius
    crAnimation.fromValue = layer.cornerRadius
    crAnimation.duration = duration // アニメーション時間
    layer.add(crAnimation, forKey: nil)
    layer.cornerRadius = radius // 終了時に元に戻ってしまわないようにします
}

また、以下のメソッドを使えばイーズインやバウンドするアニメーションを作成することも可能です。

UIView.animate(withDuration: <TimeInterval>, delay: <TimeInterval>, options: <UIViewAnimationOptions>, animations: <() -> Void>, completion: <((Bool) -> Void)?>)
UIView.animate(withDuration: <TimeInterval>, delay: <TimeInterval>, usingSpringWithDamping: <CGFloat>, initialSpringVelocity: <CGFloat>, options: <UIViewAnimationOptions>, animations: <() -> Void>, completion: <((Bool) -> Void)?>)

例えば以下のような感じです。

UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseIn, animations: {
    shutterButton.frame.size = CGSize(width: 60, height: 60)
    shutterButton.center = CGPoint(x: 45, y: 45)
}, completion: nil)
UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.2, initialSpringVelocity: 20, options: .curveLinear, animations: {
    shutterButton.frame.size = CGSize(width: 60, height: 60)
    shutterButton.center = CGPoint(x: 45, y: 45)
},completion: nil)

usingSpringWithDampingは基本値が「1」で値が小さくなるほど終点でバウンドする幅が大きくなるそうです。
initialSpringVelocityについてはよくわからないのですが、flashで良くあった揺れのようなものでしょうか。

ちなみに録画開始と停止の音を出すならサウンドIDは1117と1118です。
音を鳴らす方法はこちらをご参照ください。

Xcode: 8.3.3
Swift: 3.1
OS: Sierra 10.12

この記事がお役に立ちましたらシェアお願いします
3,451 views

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です