isExclusiveTouchで同時タップを禁止
UIButton を同時にタップすると思わぬ不具合が発生する場合があります。
それを防止するために、UIButtonの同時タップを禁止するisExclusiveTouchという設定があります。 exclusive は 排他的な という意味なので、isExclusiveTouch はタップを排他的にする設定 という意味です(デフォルトは false です)。
下記のプログラムのように、同時タップしてほしくないボタンの isExclusiveTouch を true にすると、ボタンの同時タップができなくなるので安心です。
buttonA.isExclusiveTouch = true
buttonB.isExclusiveTouch = true
Outlet Collectionでほぼ自動
しかし、ボタンが増えると、すべてのボタンに isExclusiveTouch を設定するのは大変です。そんなときに便利なのが Outlet Collection です。
Outlet Collection をつくる方法は簡単です。
通常の Outlet をつくるように、controlキーを押しながらボタンをクリックして、ストーリーボードからソースファイルにぐいっとドラッグします。するとポップアップ画面が表示されるので、 connection を Outlet Collection に変更して name に名前を入力して、 connect ボタンをクリックします。
あとは、 Outlet Collection に追加したいボタンをcontrolキーを押しながらクリックして、さきほど作成した Outlet Collection のところまでドラッグします。そうすると、ひとつの Outlet Collection に複数のボタンが登録されます。
ソースファイルでは、 Outlet Collection は下記のようになります。
@IBOutlet var exclusiveButtons: [UIButton]!
UIButton の部分が [UIButton] になっているところからわかるように、 Outlet Collection はアウトレットの配列です。配列であれば for-in がつかえるので、下記のようなコードでいっきに isExclusiveTouchを true に変更できます。
for button in exclusiveButtons {
button.isExclusiveTouch = true
}
viewDidLoad などで上の処理を実行すれば、 Outlet Collection に追加しているボタンの同時タップを禁止することができます。
デフォルト設定すれば全自動
shtnkgmさんにコメントをいただいて追記しました。ありがとうございます!
以下のように書くと UIButton 全体にデフォルト値として適用が可能だそうです。つぎに紹介する exclusiveAllTouches メソッドも便利ですが、たとえば viewDidLoad よりあとに動的に追加されたボタンへも反映できるそうです。
なにこれ素敵!
UIButton.appearance().isExclusiveTouch = true
再帰メソッドをつかえば全自動
Outlet Collection も便利ですが、ボタンを追加したときに設定し忘れるかもしれません。そんなときに便利な方法をこちらの記事で紹介していました。
viewDidLoad などで exclusiveAllTouches メソッドを呼び出せば、再帰的にすべてのボタンを検索して isExclusiveTouch を true にしてくれます。とてもいいですね。
extension UIViewController {
func exclusiveAllTouches() {
self.applyAllViews { $0.isExclusiveTouch = true }
}
func applyAllViews(apply: (UIView) -> ()) {
apply(self.view)
self.applyAllSubviews(self.view, apply: apply)
}
private func applyAllSubviews(view: UIView, apply: (UIView) -> ()) {
let subviews = view.subviews as [UIView]
subviews.map { (view: UIView) -> () in // Swiftのmapって戻り値なくても大丈夫なのね(ちょっと不気味
apply(view)
self.applyAllSubviews(view, apply: apply)
}
}
}