34

I'm using the following code to present a UIAlertController action sheet with the item text as red. I've used the tint property to set the color.

UIAlertController *alertController = [UIAlertController
                                      alertControllerWithTitle:nil
                                      message:nil
                                      preferredStyle:UIAlertControllerStyleActionSheet];
alertController.view.tintColor = [UIColor redColor];

The text color seems to be defaulting to blue on highlight or selection. Is this normal and how do I stop this?

Bcf Ant
  • 1,639
  • 1
  • 16
  • 26
  • you want to change text color as red or background color to red in all modes – Anbu.Karthik Sep 21 '15 at 10:56
  • its a bit unclear what you want to achieve but have a look here, I think you'll find the answer in this thread http://stackoverflow.com/questions/4248400/uiactionsheet-buttons-color – deimus Sep 21 '15 at 11:00
  • @deimus I've changed the text color to red for the action sheet items. Which works correctly, but when you highlight or select the actionsheet item. It's defaults to blue. I want it to stay red. – Bcf Ant Sep 21 '15 at 11:05
  • @BcfAnt If my information is sufficient for you, would you mind accepting the answer? Not my fault that it's an Apple Bug ;) – Frederik Winkelsdorf Nov 10 '15 at 18:26
  • Frederick- if the way Apple have coded this means it does not work, it is not correct for him to accept your solution. You said something similar yourself in the replies below when someone suggested a solution which does not work on rotation. – Peter Johnson May 13 '16 at 11:15
  • @PeterJohnson Missed your comment. Yes and no. There is currently no solution to solve this bug without interfering with private API. His question was "is this normal" so my answer was something like "yes, because it's a bug". I didn't meant the part of my workaround, here your statement is correct. – Frederik Winkelsdorf Oct 07 '16 at 17:18

11 Answers11

50

This is a known Bug, see https://openradar.appspot.com/22209332

To fix it, reapply the tint color in the Completion handler. Here's my Swift Solution, you will be able to adapt it easily for ObjC:

alertController.view.tintColor = UIColor.redColor() // apply 1st time to prevent flicker from Blue to Red when displaying

navigationController?.presentViewController(alertController, animated: true, completion: {
    // Bugfix: iOS9 - Tint not fully Applied without Reapplying
    alertController.view.tintColor = UIColor.redColor()
})

One Note: This does not fix the Bug entirely. You will notice upon Device Rotation that the Buttons are recolored with System Default (= Blue) tint.

Expect it to be fixed with iOS 9.1.

Edit 10/23/2015: Still not fixed with iOS 9.1. Retested with iOS 9.1 + Xcode 7.1 (7B91B) released a couple of days ago. As of now setting the .tintColor does not work, however as commented you can set the tintColor of the whole Application, e.g. in AppDelegate didFinishLaunchingWithOptions set window?.tintColor = UIColor.redColor(). This also tints the AlertController Buttons but may not be suitable in some cases as this tint is applied throughout the whole Application.

Frederik Winkelsdorf
  • 4,383
  • 1
  • 34
  • 42
  • Thanks. I'll check again when iOS 9.1 is released. – Bcf Ant Sep 21 '15 at 16:24
  • 1
    Addendum: Still not fixed with iOS 9.0.1 and 9.0.2. Waiting for iOS 9.1. As a temporary workaround one may find it suitable to set the tintColor of the whole Application in AppDelegate didFinishLaunchingWithOptions `window?.tintColor = UIColor.redColor()` as this is applied throughout the whole Application. But this might interfere with your other UI aspects. – Frederik Winkelsdorf Oct 08 '15 at 09:44
  • Still not fixed, but if you set the tint color after the presenting the view, it won't default back to the original color. See Eddy's answer below. – Bcf Ant Oct 31 '15 at 09:30
  • @Bcf Ant: Also on rotation? Afaik this also does not fix the issue, I'll check it later.. – Frederik Winkelsdorf Nov 01 '15 at 12:43
  • @frederik-a-winkelsdorf I've only tested an app that is locked to portrait. The issue might still occur if your app supports landscape too. – Bcf Ant Nov 01 '15 at 12:58
  • @BcfAnt Tested it, does not work when rotated. So Eddy's solution is not a valid fix, as mine is neither :( – Frederik Winkelsdorf Nov 01 '15 at 15:50
  • @frederik-a-winkelsdorf Is there anyway to re-apply the tint on rotation? – Bcf Ant Nov 01 '15 at 16:52
  • @BcfAnt Hmm, you could probably keep an instance Variable of the AlertController and add rotation handling to the underlying form which sends a new view.tintColor to the AlertController upon rotation. That should work but I didn't try it, imo it's not worth the additional work as rotating a View with an AlertController might be a rare corner case scenario and AND I mentioned a working workaround by setting window.tintColor for the whole App in your AppDelegate (which tint's other things too, but you might find a suitable color scheme as I did for my customers). – Frederik Winkelsdorf Nov 02 '15 at 17:39
  • here is a very good alternative to UIAlertController with great animation, this bug was really not fixed until now: github.com/AaoIi/AAAlertController – Nata Mio Jun 19 '16 at 07:31
39

Just add the tintColor after the presentViewController. Works on iOS 9.0.2

[self presentViewController:alertController animated:YES completion:nil];

[alertController.view setTintColor:[UIColor yellowColor]];
Eddy
  • 407
  • 3
  • 7
  • Use @Eddy method. Works perfectly. Thanks! – Bcf Ant Oct 31 '15 at 09:28
  • Just tested: Does not work when rotation device. Accepting this is just wrong. AlertController changes Tint back to Blue on Rotation. So this is not the correct answer ;) This code snippet works for Portrait the same way as my Completion Handler Workaround does, but please not that this solution has some Code Smell, as the Message to invoke/present the alertController might return early and setting it's View Tint this way - not in the Completion Handler - might lead to unwanted behaviour. – Frederik Winkelsdorf Nov 01 '15 at 15:54
  • @frederik-a-winkelsdorf I'm new and don't no all the rules. I accepted the answer because it solved my problem. The color was defaulting on highlight or selection. I've unaccepted the answer for now. – Bcf Ant Nov 01 '15 at 16:55
  • here is a very good alternative to `UIAlertController` : https://github.com/AaoIi/AAAlertController – Nata Mio Jun 19 '16 at 07:30
15

You can also change the app tint color in appdelegate.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window.tintcolor = [UIColor yellowColor];
    return YES;
}

works perfect for me.

marco v berlo
  • 151
  • 1
  • 2
  • 2
    Shockingly, this works. Even if you set the global tint color in the storyboard, it won't apply to any AlertControllers and if you apply the tint color to the Alerts directly, the "highlighted" state of the buttons is still default blue. However, adding the above code actually applies your tint to the alerts properly. – Travis M. Aug 31 '16 at 15:27
11

Update for Swift 4, Xcode 9

private static func setupAppearanceForAlertController() {
    let view = UIView.appearance(whenContainedInInstancesOf: [UIAlertController.self])
    view.tintColor = .black
}
Ben M
  • 2,405
  • 1
  • 20
  • 19
5

You can change button colour like this

UIAlertAction* button = [UIAlertAction
                              actionWithTitle:@"Delete Profile"
                              style:UIAlertActionStyleDefault
                              handler:^(UIAlertAction * action)
                              {
                                  //Add Action.
                              }];
[button setValue:[UIColor redColor] forKey:@"titleTextColor"];

By Using this line [button setValue:[UIColor redColor] forKey:@"titleTextColor"]; You can change the button colour of your action sheet

Kaushik Movaliya
  • 799
  • 11
  • 27
2

Set your tint color in traitCollectionDidChange in a subclass of UIAlertController.

override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)
    self.view.tintColor = UIColor.redColor()
}
laynemoseley
  • 258
  • 2
  • 6
1

To set custom color and font subclass UIAlertController like this.

import UIKit

class StyledAlertController: UIAlertController {

    private var cancelText:String?

    override func viewDidLoad() {
        super.viewDidLoad()
        view.tintColor = YourColor
    }

    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        findLabel(view)
    }

    private func findLabel(scanView: UIView!) {
        if (scanView.subviews.count > 0) {
            for subview in scanView.subviews {
                if let label:UILabel = subview as? UILabel {
                    if (cancelText != nil && label.text == cancelText!) {
                        dispatch_async(dispatch_get_main_queue(),{
                            label.textColor = YourColor
                            label.tintColor = YourColor
                        })
                    }
                    let font:UIFont = UIFont(name: YourFont, size: label.font!.pointSize)!
                    label.font = font
                }
                findLabel(subview)
            }
        }
    }
}

Use like this (as you normally would)

let StyledAlertController = StyledAlertController(title: "My Title", message: "My Message", preferredStyle: .ActionSheet)

let cancelAction:UIAlertAction = UIAlertAction(title: "Cancel", style: .Cancel) { action -> Void in
        print("Cancel Action Click")
    }
actionSheetController.addAction(cancelAction)

let anotherAction:UIAlertAction = UIAlertAction(title: "Another Action", style: .Default) { action -> Void in
        print("Another Action Click")
    }
actionSheetController.addAction(anotherAction:UIAlertAction)

presentViewController(actionSheetController, animated: true, completion: nil)
Michael
  • 9,639
  • 3
  • 64
  • 69
1

Just change your view tintAdjustmentMode to UIViewTintAdjustmentModeNormal, so it will not change it's color on dimm.

Alexander
  • 780
  • 1
  • 8
  • 22
0

I am still confused what you want to achieve. But you can try the Apple's way of creating Destructive buttons(by default text color is red).

The code where you are creating UIAlertActions don't use the Default style for the buttons you want in red color. Instead use UIAlertActionStyleDestructive. Sample Code :

UIAlertAction* cancel = [UIAlertAction
                         actionWithTitle:@"Cancel"
                         style:UIAlertActionStyleDestructive
                         handler:^(UIAlertAction * action)
                         {
                             [view dismissViewControllerAnimated:YES completion:nil];

                         }];
Vinay Jain
  • 1,653
  • 20
  • 28
0

UIAlertController is availabel iOS 8 and later , thus there is a bug for devices with older version. There's no problem for devices with corresponding or higher version.

0

To prevent the fast "popping up" of the new tint color the alpha value of the alert controller can be animated. Then it looks exactly the same as if there where no bug:

    alertController.view.alpha = 0.0
    presentViewController(alertController, animated: false) {
        alertController.view.tintColor = UIColor.redColor()
        UIView.animateWithDuration(0.2, animations: { alertController.view.alpha = 1.0 }, completion: nil)
    }
Darko
  • 9,655
  • 9
  • 36
  • 48