LoginSignup
5

More than 3 years have passed since last update.

新規にiOSアプリ開発を始めた学生エンジニアに取ってUITabBarのカスタマイズは地獄だった話

Last updated at Posted at 2017-11-16

iPhone XR, XS, XS Maxにも対応しました。

僕はもともとWeb Applicationの開発をしてた人なので、スマホアプリのUIもWebViewを使って書いていました。(正確に言うとIonicとかOnsenUIとか) Web UIでも工夫次第ではネイティブUIにひけをとらないのですが、アニメーションやデバイスセンサを扱う部分など、やはりネイティブにはかないません。
そこで、iOSのネイティブUI(UIKit)でフロントを作ろうとしたのですが「Reactヤベェ!Angularヤベェ」とWebの世界でいきっていた人にとっては辛い例があったので備忘録代わりにまとめました。

UITabBarのアイコンのタイトルを消したい

iOS標準のTabBarはこんな感じですよね。アイコンの下にタイトルがあるオーソドックスなUIです。

Screen Shot 2017-10-21 at 21.55.12.png

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

IMG_3203.jpg

最初はdisableLabel = trueのようなプロパティをfalseにすることで消えるかなっと楽観的に考えていたのですが、どうやらない!
https://developer.apple.com/documentation/uikit/uitabbaritem を見るとtitleというgetter setterプロパティがありました。
ということで、titleをoverrideしちゃいましょう。するとラベルが消えますがアイコンの位置がずれてしまうのでimageInsetsもoverrideして位置を調整します。

CustomTabBarItem.swift
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以下のバージョンもサポートすることができます。

CustomTabBar.swift
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にhexalphaの引数を持たせて内部で通常の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)
    }
}

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
5