【Swift】UiViewのタップ領域を拡張する方法!UIEdgeInsetsの使い方
この記事からわかること
- Swift/UIKitでUIViewのタップ領域を拡大する方法
- UIEdgeInsetsとは?
- CGRectContainsPointとは?
- point(inside point: CGPoint, with event: UIEvent?) -> Boolとは?
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
環境
- Xcode:15.0.1
- iOS:17.1
- Swift:5.9
- macOS:Sonoma 14.1
この記事は以下の記事を参考にさせていただき、最新のコードに書き換えて自分の理解のために解説を増やした記事になります。
参考記事: Qiita:【iOS】UIButtonのタップ領域だけを拡大する
UIViewのタップ領域を拡張する方法
UIViewにタップなどのジェスチャーイベントを付与している場合にViewの大きさはそこまで大きくしたくないがタップ判定領域だけ拡大したい場合がありました。UXを考えた時にタップしやすい設計にするためにタップ判定領域を自由にコントロールできると便利になります。
UIViewのタップ領域を拡張するためには以下のようにタップ領域を拡張できる汎用的なビュークラスを実装します。
class ExtensionTapAreaView: UIView {
var insets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0 )
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
var rect = bounds
rect.origin.x -= insets.left
rect.origin.y -= insets.top
rect.size.width += insets.left + insets.right
rect.size.height += insets.top + insets.bottom
return CGRectContainsPoint(rect, point)
}
}
その拡張ビュークラスをインスタンス化し拡大したい領域をUIEdgeInsets
で指定します。以下の場合は元のViewの大きさよりタップ領域のみを上下左右に20pxずつ拡大しています。
class ViewController: UIViewController {
private var myView: ExtensionTapAreaView!
override func viewDidLoad() {
super.viewDidLoad()
myView = ExtensionTapAreaView(frame: CGRect(x: 0, y: 0, width: 200 , height: 100))
myView.insets = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
myView.center = self.view.center
myView.backgroundColor = .gray
myView.isUserInteractionEnabled = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapped(_:)))
myView.addGestureRecognizer(tapGesture)
self.view.addSubview(myView)
}
@objc func tapped(_ sender : UITapGestureRecognizer) {
print("タップされたよ")
}
}
実装方法の解説
ExtensionTapAreaView
クラスで実装しているのがタップ領域の拡大です。オーバーライドしているpoint(inside point: CGPoint, with event: UIEvent?) -> Bool
は指定されたポイントがビューの境界内にあるかどうかを判定するメソッドです。
// 指定されたポイントがビューの境界内にあるかどうかを判定するメソッド
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { }
引数point
にはタップされた座標が渡され、その座標が自身のViewの領域内にあればtrue
をなければfalse
を返します。ここでtrue
を返すことができればViewに付与しているタップジェスチャーを発火させることができます。
Viewのタップ領域を拡張するためにUIEdgeInsets
型で拡張させたい上下左右の余白を定義しています。UIEdgeInsets
型はViewの領域を拡大/縮小する値を保持するデータクラスです。汎用性を高めるために定義時は全方向0を指定し、インスタンス化後に自身で値を変更することでタップ領域をカスタマイズすることができるようになっています。
var insets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0 )
point(inside point: CGPoint, with event: UIEvent?) -> Bool
の中では指定されたUIEdgeInsets
の値をタップ判定領域に追加していきます。bounds
プロパティから現在のViewの領域を取得し各座標をインセットを含めた値に変更していきます。
var rect = bounds
// 元のX座標より左側に広げるためマイナスする
rect.origin.x -= insets.left
// 元のY座標より上側に広げるためマイナスする
rect.origin.y -= insets.top
// 元の横幅よりインセット分左右に広げるためプラスする
rect.size.width += insets.left + insets.right
// 元の縦幅よりインセット分上下に広げるためプラスする
rect.size.height += insets.top + insets.bottom
最後にCGRectContainsPoint
クラスで引数に渡した領域内に引数に渡された座標が含まれているかを判定します。
return CGRectContainsPoint(rect, point)
これでタップ領域を拡大することができているようです。
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。