LoginSignup
1
1

More than 3 years have passed since last update.

UIButtonのタップ領域のみを拡大する (Interface Builderで領域のプレビューもする)

Last updated at Posted at 2021-03-31

はじめに

なぜやるのか

iOSアプリのボタン、デザインは良いけど、タップ領域が小さすぎて押しづらいという事、ありませんか?
例えば、下記のサンプルのボタン。ボタンのデフォルトサイズで、System Imageを設定したよくある情報ボタンです。
しっかしこれがくせ者。サイズは20x20pxとデザイン上はよくあるのですが、タップするには小さく認識に苦労します。

確かに、Appleの公開している、Apple Interface Guideline によると、ボタンサイズは少なくとも 44 x 44 px以上とする事が推奨されています。

しかし44 x 44 pxは案外大きく、ボタンのサイズを物理的に大きくするだけでは、不都合が生じる事があります。
そこで今回は、ボタンの大きさはそのままに、タップ範囲のみを拡張して、かつ Interface Builder上でプレビューしながら作れる様にUIButtonをカスタムしていきたいと思います。

UIButtonをカスタムする

ボタンの大きさはそのままに、タップ範囲のみを拡張して、かつ Interface Builder上でプレビュー可能なカスタムボタンTapAreaExpandableButtonを作成します。

import UIKit

// @IBDesignableを付与する事で、Storyboard上に設定した値が反映される
@IBDesignable 
class TapAreaExpandableButton: UIButton {
    private var _minTapArea = CGSize(width: 0, height: 0)
    private var _previewArea = false

    // @IBInspectableを付与した変数は、Interface Builder側で編集できる
    @IBInspectable var minTapArea: CGSize {
        get { return _minTapArea }
        set { _minTapArea = newValue }
    }

    @IBInspectable var previewArea: Bool {
        get { return _previewArea }
        set { _previewArea = newValue }
    }

    open override func point(inside point: CGPoint, with _: UIEvent?) -> Bool {
        if isHidden || !isUserInteractionEnabled { return false }
        return expandedArea.contains(point)
    }

    private var expandedArea: CGRect {
        let buttonSize = self.bounds.size
        let widthToAdd = max(_minTapArea.width - buttonSize.width, 0)
        let heightToAdd = max(_minTapArea.height - buttonSize.height, 0)
        return self.bounds.insetBy(dx: -widthToAdd / 2, dy: -heightToAdd / 2)
    }

    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        if previewArea { setupPreviewArea() }
    }

    private func setupPreviewArea() {
        let tapGuideView = UIView(frame: expandedArea)
        let previewLineColor = Asset.Color.themeMidGray.color.cgColor
        let lineLayer = CAShapeLayer()
        lineLayer.frame = tapGuideView.bounds
        lineLayer.strokeColor = previewLineColor
        lineLayer.lineWidth = 1
        lineLayer.lineDashPattern = [2, 2]
        lineLayer.fillColor = nil
        lineLayer.path = UIBezierPath(rect: lineLayer.frame).cgPath
        tapGuideView.isUserInteractionEnabled = false
        tapGuideView.backgroundColor = UIColor.clear
        tapGuideView.isHidden = false
        tapGuideView.layer.addSublayer(lineLayer)
        addSubview(tapGuideView)
    }
}

使い方

先に出てきた、情報ボタンが1個だけ存在するViewを例とします。このボタンは20 x 20pxと小さくタップが難しいです。

そこで TapAreaExpandableButton をカスタムクラスとして指定します。

するとプロパティ設定に TapAreaExpandableButton の項目が出現しますので、
Min Tap Areaの項目に44 x 44pxと設定して、Preview Areaの項目をONにします。
すると、下図の様に設定したMin Tap AreaがStoryBoard上でプレビューされます。
※もしプレビューが表示されない場合は、XcodeのEditor -> Automatically Refresh Designable ViewのチェックをONにしてお試しください。

おわりに

タップ可能領域をプレビューしながら設定できるため、ボタンの大きさを微調整する手間を大きく減らす事ができると思います。本記事が少しでも参考になったのであれば幸いです。

参考

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1