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 {
~略~
}
}
}
この通り。

選択されているアイテムの色を変える
これも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で表示されるページやタブアイコンの入れ替えの扱いが手軽にできるようになってからのほうが良さげ。闇が深そう……
