[iOS][Swift3.0] ボタンのシンボルをアニメーションさせるDynamicButton

アプリケーションにおけるボタンのシンボルは状況に応じて変化する場合があります。 例えば、GoogleのマテリアルデザインガイドラインのMotionのページには、システムアイコンを切り替えるサンプルが載せられています。

今回試してみたDynamicButtonは、矢印などの標準的なシステムアイコンのシンボルが用意され、それらが切り替えられるアニメーションをサポートしています。

サンプル

上記画像のシンボルはデフォルトで用意されているものです。線の太さや色などは自由に定義出来ます。また、パスを独自に書くことによって、オリジナルな図柄にすることも可能です。ライセンスはMITです。

yannickl/DynamicButton

検証環境

今回は下記環境で試しています。

Xcode 8.2.1
Swift 3.0.2
CocoaPods 1.2.0

準備

導入

CocoaPodsで追加します。

platform :ios, '9.0'
use_frameworks!

target 'ここにターゲット名' do
    pod 'DynamicButton'
end

実装

クリックするとシンボルが変更になるサンプルです。

1.UIButtonをStoryboardに配置する

001 UIButtonを配置する

2.カスタムクラスを定義する

配置したボタンに対してカスタムクラスを定義します。ClassにDynamicButton、ModuleにもDynamicButtonを設定します。

002 カスタムクラスを定義

3.レイアウトを整える

適宜、制約をつけて配置します。

003 適宜制約をつける

4.プロパティを設定する

独自プロパティとしては、線の色や太さなどが設定できます。

004 プロパティ設定

これらはコードでも設定できます。

// 線の太さ (デフォルトは2)
button.lineWidth = 1.0
// 線の色 (デフォルトは黒)
button.strokeColor = UIColor.blue
// ハイライト時の線の色
button.highlightStokeColor = UIColor.orange
// ハイライト時の背景色
button.highlightBackgroundColor = UIColor.gray

5.コードを書く

まずはボタンをOutlet接続し、Actionをつけます。初期のシンボルを設定します。そして、ボタンが押された時にシンボルをを変更しています。

import UIKit
import DynamicButton

class ViewController: UIViewController {

    @IBOutlet weak var sampleButton: DynamicButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        sampleButton.lineWidth = 3
        sampleButton.setStyle(DynamicButtonStyle.play, animated: false)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func didTapSampleButton(_ sender: Any) {
        if let button = sender as? DynamicButton {
            button.setStyle(DynamicButtonStyle.checkMark, animated: true)
        }
    }
}

ボタンのシンボルを変更するにはsetStyle(:animated)を使います。animatedをtrueにすると切り替える時にアニメーションが発生します。

実行結果

ボタンをタップすると▷からチェックマークに切り替わります。

実行結果

オリジナルな図柄を作成する

DynamicButtonStyleを継承したクラスを作成します。initで図柄のパスを4つ指定します。パスは4より多くは指定できません。また、少ない場合は同じパスを重ねると良いかもしれません。(これはアニメーションに影響します)

下記はサンプルコードです。

import UIKit
import DynamicButton

final public class SampleButtonStyle: DynamicButtonStyle {
    
    convenience required public init(center: CGPoint, size: CGFloat, offset: CGPoint, lineWidth: CGFloat) {
        let x:CGFloat       = center.x - lineWidth / 2
        let midSize:CGFloat = size / 2

        let p1 = UIBezierPath(roundedRect: CGRect(x: x - midSize + lineWidth, y: center.y - center.y / 2, width: lineWidth, height: lineWidth), cornerRadius: lineWidth / 2).cgPath
        let p2 = UIBezierPath(roundedRect: CGRect(x: x + midSize - lineWidth, y: center.y - center.y / 2, width: lineWidth, height: lineWidth), cornerRadius: lineWidth / 2).cgPath
        let p3 = CGMutablePath()
        p3.move(to: CGPoint(x: x - midSize + lineWidth, y: center.y + center.y / 2))
        p3.addLine(to: CGPoint(x: x + midSize, y: center.y + center.y / 2))

        self.init(pathVector: (p1, p2, p3, p3))
    }

    // MARK: - Conforming the CustomStringConvertible Protocol

    public override var description: String {
        return "SampleButtonStyle"
    }
}

setStyleで自分で作成したスタイルクラスを適用させます。

import UIKit
import DynamicButton

class ViewController: UIViewController {

    @IBOutlet weak var sampleButton: DynamicButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        sampleButton.lineWidth = 3
        sampleButton.setStyle(SampleButtonStyle.self, animated: false)

実行結果

顔みたいなのがカスタマイズした図柄です。

実行結果2

さいごに

デフォルトで用意されている図柄は標準的であり、線の太さや色などをカスタマイズできるので使いやすいのではないでしょうか? 状態が変化するボタンにはちょうど良いと思います。