コード
モチベーション
UIButtonをカスタマイズしようとした時、どうするでしょうか?
UIButtonはInterfaceBuilder上で、子Viewを置けません。
- UIButtonのパラメータをいじって頑張る
- すべて画像にしてしまう
- UIButtonにaddSubviewしてしまう
- Viewの上に、同じ大きさの透明なUIButtonを置く
- UIGestureRecognizerを使う
- UIButtonの親クラスであるUIControlをカスタマイズする
今回は、6を作ってみました。
利点:InterfaceBuilder上でButtonの中身に対してAutoLayoutを組める。
動き
こんな感じです。すべてUIControlのサブクラスです。

Type | 見た目 |
---|---|
componentLight | 子Viewを薄くする |
componentDark | Label以外を暗くする |
baseDark | 全体を暗くする |
lighterTheWhole | 全体の半透明にする |
likeButtonPlane | 通常のUIButton状態 ラベルだけ薄くなる |
likeButtonCustom | 通常のCustomUIButton状態 Imageが暗くなる |
whiteTheWhole | 全体が白くなる |
他にも柔軟にカスタマイズできます

selected,disable,highlightのViewをセットできます

ボタンとの比較です。似せています。

画像ボタンも簡単です。
角丸の場合は、WhiteやDarkがその形に沿っています(重要)
類似ライブラリはないのか?
私は探せませんでした。
もっと具体的な「よく使うボタン」をまとめたものはあります。
使い方

UIViewにButtonViewをClass指定してください。
UIControlでもいいですが。
そうすればいつものアレが出ます。

ボタンはタイプの設定が必要です。デフォルトではUIButtonっぽくなります。
inuButton.setup(type: .darkerTheWhole)
特定のStateに対するViewを設定する場合は以下です。あまり使わないですけど。
inuButton.setView(view: pressedInuButton, forState: .highlighted)
あまりViewの階層を深くしたり、複雑なViewを組み込んだ場合は想定していないのでどうなるかわかりません。
StackViewくらいならどうにかなると思います。
実装の中身
目標としては、UIControlとUIButtonの差分を埋めるだけです。
ただし今回はTitleやImage、BacgroundImageは不要です。
あと細かなShadowの仕様とか、Insetの仕様は詰めていません(完全に自分が普段使っていない仕様を無視している状態)
TODO一覧
- タッチした際に表示を変える
- 表示パターンのルールを作る(UIButtonに存在しないパターンもあるので)
- 範囲を外れた時、範囲に戻ったときに表示を変える
- selected,highlight,disableの時のViewをセットできるようにする
実は、イベント関連はUIButtonじゃなく、UIControlなんですよね(知らなかった)
UIControlStateはもちろんUIControlの仕様なんですが、setImage:forStateとかはUIButtonの仕様です(解せない。もしくは私が知らないだけか)
実際のコードに関しては特に面白くないので割愛します。
所感、その他
3 UIButtonにaddSubviewしてしまう
4 Viewの上に、同じ大きさの透明なUIButtonを置く
こっちの方でも似たことできそうなんですが、3はやはりInterfaceBuilderでレイアウトが組めませんし、4はイベントとの繋ぎ込みができないので使い勝手が悪そうです。
実際に半年くらい使っていますが、痒いところに手が届く感じが気に入っています。
よく「そのボタンの仕様って、iOS的じゃないんですよね〜〜」とか以前は言ってましたがもう言いません。
iconをどの位置にどの大きさで置くとかにも悩みません。
ボタンの中でアニメーションも簡単です。
あと残す面倒事はシャドーくらいです・・・