Alerts and Action Sheets not using SwiftUI accent color

I'm rebaselining my apps to require iOS 14. As such, I'm moving completely to SwiftUI to include no longer using UIKit for the application delegate logic.

Previously, in my app delegate, I would use the appearance proxy APIs to set up tint colors for various bars, switches, etc. as well as to set the tint color on my main window. So all the app's UI to include buttons on alerts and action sheets, would be using my custom color.

In my SwiftUI app, I have filled in the color swatches for the AccentColor item in my xcassets file. I have all four swatches filled: light vs. dark, normal vs. high contrast.

This works perfectly for any view controller in my app. Navigation and tab bar elements, etc. all have my accent color. However, when presenting an alert or action sheet, they are using the default system blue colors.

I don't see any way to assign accent/tint colors directly to the alerts/action-sheets. Is this not possible?

Replies

I am having this same problem to.

The accent colour does affect alerts and action sheets but for some reason they don't show up straight away.
When the alert/action sheet is presented try holding on one of the buttons and then dragging your finger off of it, so that you're not pressing the button but just interacting with it - sort of making it active. You will see that the button does take on the accent colour.

I think this is just a bug where these controls show the blue tint colour by default without consulting the asset catalog for the correct accent colour (if there is one).
Thanks for finding that highlighting issue, BabyJ. You're correct in that it appears that when initially presented, an alert or action sheet will not be using the proper accent for the button normal states. But during interaction, the accent is then used.

I have created a sample Xcode project showing the issue and filed feedback: FB8994751
  • Have you heard back from Apple on this? I am seeing this very issue developing with SwiftUI on Xcode 13.0, iOS 15.0. All other buttons seem to handle the project's accent color fine, but not alert buttons. And I am also seeing the issue where activating the alert button seems to reveal the accent color, but its initial state will always show blue.

Add a Comment

I was having the same problem for last half year, as I thought Apple will fix it before my app publication. However, it didn't happen and I had to find some way to make it working. Appears it's ease to fix with one line of code in SceneDelegate. The solution isn't perfect, as it overwrites all UIAlertController tintColor, but it works.

// SceneDelegate.swift

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
  // ...
  UIView.appearance(whenContainedInInstancesOf: [UIAlertController.self]).tintColor = UIColor(named: "AccentColor")
  // ...
}

Based on maxtomczyk's fix the following seems to works fine with "new" App (no SceneDelegate.swift) (with universal AccentColor in assets ofc)

// root app file

@main
struct MyApp: App {

  init(){
    // override apple's buggy alerts tintColor
    UIView.appearance(whenContainedInInstancesOf: [UIAlertController.self]).tintColor = UIColor(named: "AccentColor")
  }

  var body: some Scene {
    WindowGroup {
      // content view...
    }
  }

}
  • still conficts, only overriding all seems to do the job : UIView.appearance().tintColor = UIColor(named: "AccentColor")

  • This doesn't work in Xcode 14 beta. I get errors: "Cannot find 'UIAlertController' in scope", "Cannot find 'UIColor' in scope", and "Cannot find 'UIView' in scope"

  • You need to import SwiftUI or UIKit.

Add a Comment

It looks like the issue is with UIColor.tintColor.

A color value that resolves at runtime based on the current tint color of the app or trait hierarchy.

When adding this line of code:

UIView.appearance(whenContainedInInstancesOf: [UIAlertController.self]).tintColor = .tintColor

the same buggy behaviour occurs, but setting it to any other colour makes it work fine.

Apple's implementation must use UIColor.tintColor which is why alert buttons' colours are "broken".

All the solutions from this thread did not work for me when the application was in production. It only works during the development process. More over, I am not sure that adding the UIView.appearance(whenContainedInInstancesOf:) call within the @main app entry initializer is a good practice as swiftUI views call it every time the view redraws.

The trick for me was calling appearance without the parameter whenContainedInInstancesOf of appearance(), on a onAppear() modifier. It also work only when setting the color this way: UIColor(named: "AccentColor"). Calling UIColor(.accentColor)from SwiftUIColor` does not work.

@main
struct AwesomeApp: App {

  var body: some Scene {
    WindowGroup {
      Group {
        ContentView()
      }
      .onAppear { UIView.appearance().tintColor = UIColor(named: "AccentColor") }
    }
  }
}