【SwiftUI】Listの背景色を変更する

2022.05.13

SwiftUIでListを使用すると背景色はデフォルトで薄いグレーのようなカラーになっています。デフォルトの色以外に変更したかったので調べることにしました。

環境

  • Xcode 13.3

デフォルトの色

Listを表示してみました。

import SwiftUI

struct ContentView: View {

    var body: some View {
        List {
            Text("あれ?")
            Text("声が")
            Text("遅れて")
            Text("聞こえてるよ")
        }
    }
}

デフォルトでは、このようなグレーの色になっております。

色を変更させようとして.tint.backgroundを使用しても変更出来ませんでした。

UITableView.appearance().backgroundColorを使用する

Listの背景色を変更させるためにUITableView.appearance().backgroundColorを使用します。

import SwiftUI

struct ContentView: View {

    init() {
        UITableView.appearance().backgroundColor = .orange
    }

    var body: some View {
        List {
            Text("あれ?")
            Text("声が")
            Text("遅れて")
            Text("聞こえてるよ")
        }
    }
}

initメソッド時にUITableView.appearance().backgroundColorに変更したい色を代入しています。

これでListの背景色が変更出来ました。

Listのextensionを作成する

上記で記載した方法をextensionメソッドを作成して実施してみます。

UITableView.appearance().backgroundColorに変更したい色を代入して、Viewを返すメソッドをListの extensionとして作成します。今回はListのexntensionですがFormなども該当する為、Viewのextensionでも良いかもしれません。

import SwiftUI

extension List {

    func listBackground(_ color: Color) -> some View {
        UITableView.appearance().backgroundColor = UIColor(color)
        return self
    }
}

Listのextensionを使用する

作成したextensionメソッドを使用する際は下記のように使用します。

import SwiftUI

struct ContentView: View {

    var body: some View {
        List {
            Text("あれ?")
            Text("声が")
            Text("遅れて")
            Text("聞こえてるよ")
        }
        .listBackground(.blue)
    }
}

同じようにListの背景色が変更出来ました。

NavigationViewと一緒に使用してみると

NavigationView.listBackground(_ color:)を一緒に使用してみました。

import SwiftUI

struct ContentView: View {

    var body: some View {
        NavigationView {
            List {
                Text("あれ?")
                Text("声が")
                Text("遅れて")
                Text("聞こえてるよ")
            }
            .listBackground(.yellow)
            .navigationTitle("Title")
        }
    }
}

.listBackground(_ color:)で指定したカラーがNavigationViewの範囲まで反映されます。

UITableView.appearance()の問題点

UITableView.appearance().backgroundColorを使うと、全てのListの背景色が変更されます。

例として、最初に黄色のListを表示させて、NavigationBarのボタンを押すと、赤色のListに遷移してみます。

コード

ContentView(Yellow)

import SwiftUI

struct ContentView: View {

    var body: some View {
        NavigationView {
            List {
                Text("あれ?")
                Text("声が")
                Text("遅れて")
                Text("聞こえてるよ")
            }
            .listBackground(.yellow)
            .navigationTitle("Yellow")
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    NavigationLink {
                        NextView()
                    } label: {
                        Image(systemName: "chevron.right")
                    }
                }
            }
        }
    }
}

NextView(Red)

import SwiftUI

struct NextView: View {

    var body: some View {
        List {
            Text("いいえ")
            Text("普通に")
            Text("聞こえてるよ")
        }
        .listBackground(.red)
        .navigationTitle("Red")
    }
}

結果

最初にNextViewに遷移した際には、Listの色の変化は適用されますが、その色の変化が全てのListに反映されるので前画面(ContentView)に戻った際に黄色で表示させたいはずのListが赤色になってしまいました。

Simulator Screen Recording - iPod touch (7th generation) - 2022-05-11 at 16 47 09

ルートビューでListの背景を透明にする方法

それぞれでUITableView.appearance().backgroundColorを設定すると意図した状態になりませんでした。

これの対策として、まずルートビューでUITableView.appearance().backgroundColorを透明にしておきます。

import SwiftUI

@main
struct KoeGaOkureteruyoApp: App {

    init() {
        UITableView.appearance().backgroundColor = .clear
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

backgroundにColorを指定する

.listBackground(_ color:)のコードを削除して、.backgroundに置き換えます。

ContentView(Yellow)

import SwiftUI

struct ContentView: View {

    var body: some View {
        NavigationView {
            List {
                Text("あれ?")
                Text("声が")
                Text("遅れて")
                Text("聞こえてるよ")
            }
            .background(.yellow) // .backgroundに変更
            .navigationTitle("Yellow")
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    NavigationLink {
                        NextView()
                    } label: {
                        Image(systemName: "chevron.right")
                    }
                }
            }
        }
    }
}

NextView(Red)

struct NextView: View {

    var body: some View {
        List {
            Text("いいえ")
            Text("普通に")
            Text("聞こえてるよ")
        }
        .background(.red) // .backgroundに変更
        .navigationTitle("Red")
    }
}

結果

それぞれのListで意図した背景色を確認出来ました。

Simulator Screen Recording - iPod touch (7th generation) - 2022-05-11 at 16 49 34

おわりに

appearance()を使用すると全てのListに影響与えてしまうことが変わり、色々と考慮しながら使う必要があることが分かりました。もし、他に良い方法等ありましたら教えていただけると嬉しいです。

いつかSwiftUIだけで容易に背景色が変更できるようになると良いね。

参考