iPhone XR, XS, XS Maxにも対応しました。
僕はもともとWeb Applicationの開発をしてた人なので、スマホアプリのUIもWebViewを使って書いていました。(正確に言うとIonicとかOnsenUIとか) Web UIでも工夫次第ではネイティブUIにひけをとらないのですが、アニメーションやデバイスセンサを扱う部分など、やはりネイティブにはかないません。
そこで、iOSのネイティブUI(UIKit)でフロントを作ろうとしたのですが「Reactヤベェ!Angularヤベェ」とWebの世界でいきっていた人にとっては辛い例があったので備忘録代わりにまとめました。
UITabBar
のアイコンのタイトルを消したい
iOS標準のTabBarはこんな感じですよね。アイコンの下にタイトルがあるオーソドックスなUIです。

しかし、InstagramのTabBarのようにアイコンのみのシンプルなものが欲しい場合もあるでしょう。

最初はdisableLabel = true
のようなプロパティをfalse
にすることで消えるかなっと楽観的に考えていたのですが、どうやらない!
https://developer.apple.com/documentation/uikit/uitabbaritem を見るとtitle
というgetter setterプロパティがありました。
ということで、title
をoverrideしちゃいましょう。するとラベルが消えますがアイコンの位置がずれてしまうのでimageInsetsもoverrideして位置を調整します。
import UIKit
class CustomTabBarItem: UITabBarItem {
override var title: String? {
get {
return nil
}
set {
super.title = title
}
}
override var imageInsets: UIEdgeInsets {
get {
return UIEdgeInsets(top: 5, left: 0, bottom: -5, right: 0)
}
set {
super.imageInsets = imageInsets
}
}
}
iOS11ではUIEdgeInsetsを調整してもアイコンが天地中央にならない!
こんな感じです。要はtop, bottom, right, left全て0にすると言うことです。
#available
を使ってiOS11のみoffsetを0にすることでiOS11以下のバージョンもサポートすることができます。
class CustomTabBar: UITabBar {
override func layoutSubviews() {
super.layoutSubviews()
var offset: CGFloat = 6.0
if #available(iOS 11.0, *), traitCollection.horizontalSizeClass == .regular {
offset = 0.0
}
let imageInset = UIEdgeInsets(
top: offset,
left: 0.0,
bottom: -offset,
right: 0.0
)
for tabBarItem in items ?? [] {
tabBarItem.title = ""
tabBarItem.imageInsets = imageInset
}
}
UITabBar
の高さを変更したい
TabBarの高さをカスタマイズするにはUITabBarの継承クラスを作りfunc sizeThatFits
をoverrideします。
この時に注意したいのがiPhone XやXR, XSという変な画面の余計な端末素晴らしく画期的な端末向けのレイアウトです。今までホームボタンがあった場所が画面になっているのでその分の高さを取得してTabBarの高さに加えてやらないと、TabBarがiPhone Xの丸っこいエッジに落ちて悲惨なことになります。
追記
self.safeAreaInsets.bottom
でセーフエリアの下の高さを取得することができますが、この値はviewWillLayoutSubviews
が実行された後に更新されます。つまり、viewWillLayoutSubviews
これが実行される前は0が返ってくるのでUIApplication.shared.windows[0].safeAreaInsets.bottom
を用います。
import UIKit
class CustomUITabBar: UITabBar {
// ここでTabBarの高さを設定
let tabBarHeight: CGFloat = 70
override func sizeThatFits(_ size: CGSize) -> CGSize {
super.sizeThatFits(size)
let safeAreaBottom = UIApplication.shared.windows[0].safeAreaInsets.bottom
var size = super.sizeThatFits(size)
if #available(iOS 11.0, *) {
size.height = safeAreaBottom + tabBarHeight
} else {
size.height = tabBarHeight
}
return size
}
}
アイコンのカラーを変えたいけどRGB表記だるいわ
iOS界隈では割と一般的な工夫かもしれませんが、UIColorを指定したい場合はUIColor(red:0.20, green:0.20, blue:0.20, alpha:1.0)
のようにRGB + Alphaで指定しなければなりません。僕みたいにWeb作ってたマンからすると面倒で仕方ない。CSS(まぁSass使いますけど)みたいに#333333
と16進で指定したいところです。
実装としてはUIColor
を拡張してinitializerにhex
とalpha
の引数を持たせて内部で通常のRGBに直します。ポイントはhexをString
としてとることです。数値型だと0x
を先頭につけなければなりません。CSSいじってたマンにとっては0xFFFFFF
なんてちょっとキモイですね。
import UIKit
extension UIColor {
convenience init(hex: String, alpha: CGFloat = 1.0) {
if hex.count == 6 {
let red: CGFloat = CGFloat((rgb & 0xFF0000) >> 16) / 255.0
let green: CGFloat = CGFloat((rgb & 0x00FF00) >> 8) / 255.0
let blue: CGFloat = CGFloat(rgb & 0x0000FF) / 255.0
}
self.init(red: red, green: green, blue: blue, alpha: alpha)
}
}