うるおいらんど

【Swift 3】UIViewの重なり方を変えずに奥側のボタンを押したかった話【hitTest】

SwiftUIView

追記があります。

(●´・ω・`●)ノ.:゚+ドモ.: *:・

とあるView上に配置したサブビューは触れるけれど、そのView自身は触れないぞ!ってのをやりたくて、やっと実装できたのでメモメモ。

例えば下図のような時

 

こういう重なり方をしているとき、通常は①のButtonをタップすることができません。

例えば②の方UIViewで

view.isUserInteractionEnabled = false

とした場合、①の方のButtonは押せるようになりますが、今度は②のButtonが押せなくなります。

 

つまり、この重なり方を変えずに、どちらのボタンも押せるようにしたい!というわけです。

これはUIViewのサブクラスなら何でも当てはまるので、UIScrollViewやUITableViewでも同様です。

 

サブクラスを作ってhitTest(_:with:)をoverrideしよう!

上記の図で両方のボタンを押せるようにする方法です。

重なっているviewを透過するようなイメージで、そのview上にaddSubviewしたものは触ることができ、何も置いていない部分は無視して、その奥にあるものをタッチできるようになります。

 

UIViewのサブクラスを作ります(UIScrollViewやUITableViewやその他諸々UIViewのサブクラスのサブクラスでもおk)

今回はUIViewのサブクラスをContentViewという名前で作っています。

import UIKit

class ContentView: UIView {
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    override init(frame: CGRect) {
        super.init(frame:frame)
        
    }
    
    //自分自身はサワレナイ
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        let view = super.hitTest(point, with: event)
        
        if view == self {
            return nil
        }
        return view
    }
}

 

タッチされたビューが自分自身だったときはviewは何も返しません。

 

この処理を透過したいビューに書くだけでおkです。

こちらの記事に感謝感謝です。

https://ssdkfk.wordpress.com/2013/06/26/hittestをオーバーライドして、uiviewのタッチ判定を無視/

 

 

色々迷走したんですが(そもそも透過するっていうアイディアが出てこなかった)これで無事解決しました〜。ワッショ━━∩(´∀`∩(´∀`∩(´∀`∩(´∀`∩(´∀`∩)━━イ!!

UIViewの重なり方を変えずに!っていうのが結構肝で、UIPageViewControllerを使っていると、固定したいビューとページングさせたいビューとなんやらかんやらで、そもそも重なり方が変えられなかったんですね。

UIPageViewControllerのviewと、そこにのせるUIViewControllerのview(ページごと)とで、重なり方が超厄介でした。

PageViewControllerの方のviewが一番上になり、UIViewControllerのviewが裏側になるんですね。前者の方のviewに全てのページに共通するオブジェクトを置いているときに、今回のやり方が必要になりました。

重なり方を変えたくてもできなくて、そこで迷走してました。多分重なり方を変えたらそれはそれでページングしなくなったり、別物を触れなくなったりするんだろうなーという感じで、今回はこれが最善かなぁといった感じ・・・

 

とりあえずは解決できてよかったです。ではでは

Additional Notes追記

Swift4での動作チェック済みです〜。

一応gistにもあげた。あげるほどでもないけど。

覚えておくと超便利!

Comments

コメントはありません。

現在コメントフォームは工事中です。