TabViewのItemを修飾する

SwiftUIはいじり甲斐があって楽しい。

前回TabViewに挑戦したときの課題

TabViewを使ってみようで出てきた残念なこと2点

  • ツールバーのアイコンを装飾できない
  • タブをいっぱい並べるとある意味余計なことをしてくれる

この内、1つ目のツールバーのアイコンを装飾できない件について、勝負を挑んでみました。

色については適当に決めたので突っ込まないでください。実際に使うときは全体のバランスを見ながら考えてください。

ところで、TabViewの下の部分はツールバーでいいんでしょうかね?タブバーっていうんでしょうかね?
どっちでもいいですね。わかりさえすれば。

ツールバーの背景色を変える

TabViewのモディファイアに良き感じのものがなかったので、UIKitを頼ることにしました。
initメソッドにてUITabBar.appearance().backgroundColorに色を設定するだけです。

struct ContentView: View {
    init() {
        UITabBar.appearance().backgroundColor = .green
    }
    var body: some View {
        TabView {
            ~略~
            }
    }
}

この通り。

色がついた!

ツールバーのうち、選択されていないアイテムの色を変える

これもUIKitを頼ることにしました。
initメソッドにてUITabBar.appearance().unselectedItemTintColorに色を設定するだけです。

struct ContentView: View {
    init() {
        UITabBar.appearance().unselectedItemTintColor = .purple
    }
    var body: some View {
        TabView {
            ~略~
            }
    }
}

この通り。

Tab3を選択した状態

選択されているアイテムの色を変える

これもUIKitを頼(以下略)

initメソッドにてUITabBar.appearance().selectionIndicatorImageにUIImageを設定するだけです。

struct ContentView: View {
    init() {
        let width = UITabBarController().tabBar.frame.size.width / 4
        let height = UITabBarController().tabBar.frame.size.height
        let barColor = UIImage().makeUnderlineImage(color: UIColor(red: 21/255.0, green: 21/255.0, blue: 21/255.0, alpha: 1.0), size: CGSize(width:width, height:height))
        UITabBar.appearance().selectionIndicatorImage = barColor
    }
    var body: some View {
        TabView {
            ~略~
            }
            .accentColor(.white)
    }
}

このような感じになります。

選択したアイテムの背景色とアイコンの色が変わっています。

注意点

なお、accentColorモディファイアは選択時の色(TintColor?)を設定します。ここだけSwiftUIを使うのもどうかと思いましたが、できればSwiftUIに寄せていきたいなということで、こうなりました。

4行目にマジックナンバーが入っていますが、これはタブのアイテム数です。
自動的に取得できればいいのですが、処理の順序などを考えると、マジックナンバーにせざるを得ないのかなと思います。せっかくSwiftUIでお気軽にTabViewを作ることができるのに、余計なところでひと手間必要になるのはもどかしい。

また、makeImageはUIImageに生やしたextensionです。やっつけ仕事でちゃちゃっと作りました。

func makeImage(color: UIColor, size: CGSize) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    color.setFill()
    UIRectFill(CGRect(x:0, y:0, width:size.width, height:size.height)
    let image = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
    return image
}

ツールバー上部の細っそい線を消したい

地味に気になるあれです。

この細いやつ
struct ContentView: View {
    init() {
        UITabBar.appearance().layer.borderWidth = 0.0
        UITabBar.appearance().layer.borderColor = UIColor.clear.cgColor
        UITabBar.appearance().clipsToBounds = true
    }
    var body: some View {
        TabView {
            ~略~
            }
    }
}

いなくなりました 😀

解決を見送る項目

もう一つの残念な点のことです。

タブ数が一定数(iPhone11 Simulatorで5つ以上)のときにMoreというアイテムが表示される件は、今回見送り。ひとまずMoreが表示される数より少ないタブ数にしておくことにする。

Moreで表示されるページやタブアイコンの入れ替えの扱いが手軽にできるようになってからのほうが良さげ。闇が深そう……

Working Around the Shortfalls of SwiftUI’s TabView
The 6-tab problem, and how to use UITabBarController to solve it
タイトルとURLをコピーしました