StoryBoard無しでUIButtonのアニメーションを実装【Swift/iOS】

技術

こんにちは。ざわかける!のざわ(@zw_kakeru)です。
StoryBoardを使わずにUIButtonの基本的な挙動を実装してみます。
UIButtonは非常によく使うクラスなので、extensionで実装しておくのがいいでしょう。
たまにはこういう初歩的な解説もありかなと思って書いてみました。
StoryBoardじゃやりたいことができないからコードで実装したい!というちょっと開発に目覚めつつある人はぜひ参考にしてください。

やりたいこと

iOSアプリ定番の青枠で青い文字、タップすると「押した」アニメーションが出るボタンを実装します。

この一番シンプルなボタンの挙動です。
.systemプロパティを使えば簡単に設定が行えますが、その場合は細かい拡張や挙動変更ができず不便なので自分でスクリプトを組んで作ってみましょう。
なお、StoryBoardは使わずにコードで実装します。
(筆者ざわは雑魚過ぎてStoryBoardの使い方が分からないんです。。。)

動作環境

Swift: 5.5
XCode: 13.0
Sumilator:  iPod touch (7th generation)

スクリプト

スクリプトは以下です。
コードをコピペして実行すると画面上に先述のボタンが表示されます。

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let button:UIButton = UIButton(frame: CGRect(x: 50, y: 50, width: self.view.frame.width/4, height: self.view.frame.height / 8))
        button.setTitle("button", for: .normal)
        button.layer.cornerRadius = 5.0
        button.layer.borderColor = UIColor.systemBlue.cgColor
        button.layer.borderWidth = 1.0
        button.setTitleColor(.systemBlue, for: .normal)
        button.addTarget(self, action: #selector(pushButton), for: .touchUpInside)
        self.view.addSubview(button)

    }

    @objc func pushButton(sender: UIButton){
        print("pushed.")
    }
}

public extension UIButton {
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
       super.touchesBegan(touches, with: event)
        touchStartAnimation(p: self)
    }
    
    override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesCancelled(touches, with: event)
        touchEndAnimation(p: self)
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesEnded(touches, with: event)
        touchEndAnimation(p: self)
    }
}

func touchStartAnimation(p: UIButton, duration: CGFloat = 0.1){
    UIView.animate(withDuration: duration,
        delay: 0.0,
        options: UIView.AnimationOptions.curveEaseIn,
        animations: {() -> Void in
            p.transform = CGAffineTransform(scaleX: 0.95, y: 0.95);
            p.alpha = 0.7
        },
        completion: nil
    )
}

func touchEndAnimation(p: UIButton, duration: CGFloat = 0.1){
    UIView.animate(withDuration: duration,
        delay: 0.0,
        options: UIView.AnimationOptions.curveEaseIn,
        animations: {() -> Void in
            p.transform = CGAffineTransform(scaleX: 1.0, y: 1.0);
            p.alpha = 1
        },
        completion: nil
    )
}

extensionを用いてUIButtonクラスに拡張機能としてtouch関連のメソッドの挙動にアニメーションを上書きし、viewDidLoad()内でボタンの生成と設定を行っています。

アニメーション自体はクラスの外にメソッドとして定義しておきます。
内容としては、ボタンを押した時に大きさを0.95倍するとともに色(透明度)を上げています。そしてボタンから指が離れるとその逆の処理を行っています。
ボタンの形や色などの細かい設定も.systemを使わずにベタ書きしているので、様々なカスタマイズが可能になっています。

終わりに

開発に少し慣れてくると、公式にあらかじめ用意されている機能だけでは自分が思った通りの見た目や挙動をしてくれないことが多々あります。
そんな時には結局パーツを自力で作ることになるので、公式ドキュメントを読みながら確認することが大事になってきます。
記事執筆のためにかなり簡略化してスクリプトを載せていますが、私は普段はこのUIパーツをさらに別クラスでラッピングしたり、引数で挙動を調整できるように変更したりなどして開発に使っています。

普段から頻繁に使うのにあんまり情報が出てこない機能ってかなりたくさんありますよね。
ボタンなんてアプリ作る人は絶対使ってるはずなのに、みんなどうやって実装してるんだろう。。
この記事も完全に我流実装なので普通こうするとかあれば誰か教えてください。。

Swiftの場合こういう初歩的な実装だと特に、キーワードでググってもStoryBoardを使った実装例ばかり出てきてしまいます。
本格的な開発者の皆さんはほとんど使わないと思いますので、コードオンリーのやり方を書いておきました。
でもやっぱり長い目で見るとStoryBoard使えるようになっといた方がいいのかなあ。分からん。
以上です。

タイトルとURLをコピーしました