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

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

とある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です。

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

hitTestをオーバーライドして、UIViewのタッチ判定を無視して下のビューにタッチする

 

 

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

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

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

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

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

 

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

 

 

 

2018/04/13追記
Swift4での動作チェック済みです〜。

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

覚えておくと超便利!
Swift ,
コメントは認証制です。詳しくは下記の注意をお読みください。お気軽にコメントお願いします!

Write a Comment

コメント時の注意

「Twitter」「Facebook」「Google+」「WordPress」のいずれかのアカウントをお持ちの方は各アカウントと連携することでコメントできます。 コメントしたことはSNSに流れませんので、アカウントをお持ちの方はこちらの方法でコメントを投稿して下さると嬉しいです。 アカウントをお持ちでない方はメールアドレスで投稿することができます。 初回コメント時は承認後に表示されます。

Related Memo...

UITableView.RowAnimation の .none はアニメーションするよ

UITableView.RowAnimation の .none はアニメーションがnoneなわけじゃなく、デフォルトの設定を使うよという意味らしい。

The inserted or deleted rows use the default animations.

なのでアニメーションしちゃう。今更の気づき。

 

iOS

UINavigationController + UIScrollView の組み合わせで使っている時に謎の余白ができる時

UINavigationController + UIScrollView の組み合わせで使っていて、UIScrollView 上に AutoLayout で上下左右0で View を設置しているのに、30px程度上にずれてしまうとき。

`navigationController.navigationBar.isTranslucent = false` にすると直るかもしれない。

ScrollView上のコンテンツとNavigationBarの重なっているところが透過していたら多分これで直せるはず。

通常のターゲットではちゃんと動いているのに、iOSSnapshotTestCase を用いたテストでだけこの対応が必要なのよくわからないけれど。。。

iOS

記事を書くほどでもないけれどメモっておきたいこと

テスト投稿。

例えばiphone7 の画面サイズ

750 × 1334
半分375 × 667

iOS
more