🥧

SwiftUIでAccentColorが上手く効かない件

2023/05/01に公開

はじめに

Swiftの勉強を始め触ると色が変わる怪しい挙動でしたので、開発における備忘として残します。
他にもあるかもですが、activeSheet, confirmationDialogにて本現象が確認できています。

環境

  • Swift: 5.7
  • Xcode:14.2

リポジトリ

https://github.com/yuya-morimoto/accent-color-demo

現象

起動画面に配置されているボタンは色がオレンジですが、Alert, ActiveSheet, ConfirmationDialogのボタンカラーは標準の水色でタップすると何故か色が変わる...

gif-mov

設定と実装

1. アクセントカラー設定

今回は変化がわかりやすいようにオレンジを設定しました。ここのアクセントカラーをアップルに馴染みのある水色?のようなカラーを変更することができます。

2. 実装

基本コピペで動くかと思います。
Appleの公式を参考にButtonを押すとAlert, ActiveSheet, ConfirmationDialogが開くようなサンプルコードです。

https://developer.apple.com/documentation/swiftui

ContentView.swift
import SwiftUI

struct ContentView: View {
    @State private var isShowAlert = false
    @State private var isShowActionSheet = false
    @State private var isConfirmationDialog = false

    var body: some View {
        VStack {
            // MARK: - Alert

            Button("Alert") {
                isShowAlert = true
            }
            .alert(isPresented: $isShowAlert) {
                Alert(
                    title: Text("Current Location Not Available"),
                    message: Text("Your current location can’t be " +
                        "determined at this time.")
                )
            }.padding()

            // MARK: - Action Sheet

            Button("ActionSheet") {
                isShowActionSheet = true
            }
            .actionSheet(isPresented: $isShowActionSheet) {
                ActionSheet(title: Text("Resume Workout Recording"),
                            message: Text("Choose a destination for workout data"),
                            buttons: [
                                .cancel(),
                                .default(
                                    Text("Append to Current Workout"),
                                    action: {}
                                ),
                                .destructive(
                                    Text("Overwrite Current Workout"),
                                    action: {}
                                )
                            ])
            }.padding()

            // MARK: - Confirmation Dialog

            Button("Import File") {
                isConfirmationDialog = true
            }
            .confirmationDialog(
                "Are you sure you want to import this file?",
                isPresented: $isConfirmationDialog
            ) {
                Button {
                    // Handle import action.
                } label: {
                    Text("""
                    Confirmation Dialog Sample!
                    """)
                }
                Button("Cancel", role: .cancel) {}
            }.padding()
        }
        .padding()
    }
}

3. アクセントカラーを指定

{project-name}App.swift
import SwiftUI

class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool
    {
    // MARK: - ここで色を指定する!!!
        UIView.appearance(whenContainedInInstancesOf: [UIAlertController.self]).tintColor = UIColor(Color("AccentColor"))
        return true
    }
}

@main
struct accent_color_demoApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

4. 修正後動作

さいごに

これが正しいのかわかりませんが、とりあえず対応できました。
Swift触って数週間ですが割と開発しやすい。

ついでに、TCA良いのでお勧めしておきます。
https://github.com/pointfreeco/swift-composable-architecture

Discussion