【iOS】【小ネタ】UIButtonは同時押しが出来る!!!
こんぬづは、案件が一段落してブログフィーバータイム入ってる無双モード田中です。
今回は小ネタとして、UIButtonが同時押しできちゃう話です。
UIButtonは同時押しが出来る!!!
UIButtonといえば.TouchUpInsideをイベントトリガーとして処理を実行するというパターンがとても多いかと思われますが、例えば二つのボタンを同時にTouchUpInsideしてしまうと両方の処理も実行したりとか、意図しない動きをすることがあります。 これは注意が必要です。
例えば以下二つなど。
- ①:完了までに時差のない処理
- ②:View要素のアニメーションによる描画・遷移などの完了までに時差のある処理
それぞれの対応法をちょっと考えてみました。
①の対処
処理の完了までに時差のない類のもので、同時押しさせたくないView要素に対しては以下の一行でオーケー。
button.exclusiveTouch = true
同時押しを禁止するプロパティです。
②の説明
これが厄介です。 例えばこんな場面です。
画面下部にタブがあり、何らかのView要素を表示するボタンがある。 よくある例だと思います。 ここで問題なのはこのView要素を表示するボタンがrootViewControllerのview配下のViewを生成・アニメーションありで表示してしまう場合などです。(UITabBarの上にViewをかぶせてしまいたい時など) 図で示すとよくわかりやすいかもしれません、例えばこんな時。
TabBarより上に乗るView要素が下からであったり、横からであったり、とりあえずアニメーションしながら出てくる時。
ソースコードではたとえばこんな実装になるでしょう。
@IBAction func tapButton(sender: AnyObject) { // keyWindowのrootViewControllerを取得して、そのviewプロパティにView要素を乗せる let rootVC = UIApplication.sharedApplication().keyWindow?.rootViewController let someViewHeight: CGFloat = 200 let someView = UIView() someView.frame = CGRectMake(0, view.frame.size.height, view.frame.size.width, someViewHeight) someView.backgroundColor = UIColor.lightGrayColor() rootVC?.view.addSubview(someView) UIView.animateWithDuration(0.3, animations: { someView.frame.origin.y -= someViewHeight }) }
ここまで長く間を挟みましたが②のパターンで問題になるのは、同時押しは先述したexclusiveTouchで防いだとしても、ボタンを押した後、Viewがアニメーションしながら描画されるまでは他の操作を受け付けてしまうようになっているところです。 特にこの例のようにrootViewControllerのview上に描画するとなると、タブごとのVCとか関係なく描画されるので、ボタンを押した後素早くタブを押したりすると意図しない箇所でそのViewが表示されたままになり、アプリが再起不能になったりします。
同じようなものだと以下の図のようなものも考えられるでしょう。 これはNavigationControllerで遷移が繋がっているところで「戻るボタン」と「View表示ボタン」を同時押ししたりする場面です。
②の対処
②を対処するには例えば
- アニメーション完了・遷移完了をハンドリングして、それまで他の処理を実行不可にして制御してやる
- 透過背景をアニメーション無しで先に描画して、その後で目的のViewを描画する
後者はPicker表示時なんかだとよくやる処理かもしれません。 あとはalpha値はデザインと応相談ですね。
まとめ
まさかUIButtonが同時押しできるなんて、知らなかった...。 ボタン同時押しなんて、試されるアプリ感強いですが以外とアプリを一度落とさないといけなかったりすることも起こりうるのでしっかり対処しておきたいところ。 「そもそもそういう設計はナンセンス」とか「再現性低いし(試そうと思って試す人しかやらない)」って意見もあると思う楽しい箇所だと個人的に思います。