Change Text Color of Items in UIActionSheet - iOS 8
Asked Answered
I

10

41

I had been using following code to change text color of items which I add in UIActionSheet.:

- (void)willPresentActionSheet:(UIActionSheet *)actionSheet {
    for (UIView *subview in actionSheet.subviews) {
        if ([subview isKindOfClass:[UIButton class]]) {
            UIButton *button = (UIButton *)subview;
            [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        }
    }
}

It works fine in iOS7, but in iOS8 the above code doesn't change the text color of items.

Now my question is how to change the text color of items which I add in UIActionSheet using iOS8??

Additional Info:
I added breakpoint to see whether following lines from the above code get executed or not:

UIButton *button = (UIButton *)subview;
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];

These lines do not get executed. So, if([subview isKindOfClass:[UIButton class]]) is always false for all items of actionSheet.subviews. So what I think is that the view heirarchy of UIActionSheet has been changed.

Ilk answered 11/6, 2014 at 4:52 Comment(8)
The view hierarchy has indeed been changed, and you should not be using UIActionSheet at all anymore in iOS 8. Use UIAlertController instead.Churning
Is there a way to change text color of 'UIAlertAction's if I use 'UIAlertController'??Ilk
@borrrden: There is no NDA this year.Churning
@ScottBerrevoets There is an NDA it is just more relaxed. It still applies to things that were not discussed at WWDCSekyere
meta.stackexchange.com/questions/94465Danseuse
For those of us who have to maintain 6/7 compatibility, this is a very relevant question. ios8 has turned even my normal action sheet's text unreadably white and I am at a loss for why.Danseuse
Try to use UIPopoverController and create a customize view in it.Maddening
@SalmanZaidi did you try my answer below? If it works for you, please mark this question as answered - thanks! https://mcmap.net/q/176752/-change-text-color-of-items-in-uiactionsheet-ios-8Geodesy
E
40

There's an easy way if you still want to use UIActionSheet instead of UIAlertController in order to support older iOS versions.

UIActionSheet actually uses UIAlertController in iOS 8, and it has a private property _alertController.

SEL selector = NSSelectorFromString(@"_alertController");
if ([actionSheet respondsToSelector:selector])
{
    UIAlertController *alertController = [actionSheet valueForKey:@"_alertController"];
    if ([alertController isKindOfClass:[UIAlertController class]])
    {
        alertController.view.tintColor = [UIColor blueColor];
    }
}
else
{
    // use other methods for iOS 7 or older.
}

For Swift Below code should works

let alertAction = UIAlertAction(title: "XXX", style: .default) { (action) in

     }

    alertAction.setValue(UIColor.red, forKey: "titleTextColor")
Ethyne answered 6/11, 2014 at 2:2 Comment(4)
Using private properties will probably get the app rejectedAfroasian
To do this correct you should use UIActionSheet and UIAlertView on iOS7 and below and UIAlertController on iOS8 and above. For my projects I wrote a 'custom' AlertController that automatically picks the right method based on the OS version. To bad I cannot share but I would definitely recommend doing this also because there are some bugs that might occur on iOS8 when using UIActionSheetEskil
Will this be rejected by apple? If I use this?Disembodied
Great, but how do you know that pro ?Singsong
G
34

To change the button title color you need to use UIAlertController and set the tintColor of the main view.

Example of setting the button title colors to black:

UIAlertController *actionSheetController = [UIAlertController alertControllerWithTitle:@"How would you like to proceed?" message:@"" preferredStyle:UIAlertControllerStyleActionSheet];

UIAlertAction *finish = [UIAlertAction actionWithTitle:@"Finish" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action)
                               {
                                   [self performSelector:@selector(finish:) withObject:nil];
                               }];

UIAlertAction *playAgain = [UIAlertAction actionWithTitle:@"Play Again" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action)
                            {
                                [self performSelector:@selector(playAgain:) withObject:nil];
                            }];

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

[actionSheetController addAction:finish];
[actionSheetController addAction:playAgain];
[actionSheetController addAction:cancel];

//******** THIS IS THE IMPORTANT PART!!!  ***********
actionSheetController.view.tintColor = [UIColor blackColor];

[self presentViewController:actionSheetController animated:YES completion:nil];
Geodesy answered 11/9, 2014 at 20:17 Comment(11)
This is a great answer. Although, I'm still looking for a way to set each button tint as well as the backgroundColor of the UIAlertController. Any thoughts?Raindrop
@Raindrop I remember reading somewhere that Apple doesn't want you to customize action sheet / alert colors. I believe that if you want to do more customizations than what I mentioned you'd need to make your own alert class, or borrow one of the many readily available open source options from github.Geodesy
Yes, that's what I thought. Actually, I do use UIView with buttons for this purpose sometimes, but it would be a lot easier to just customize UIAlertController. Thanks a lot. @GeodesyRaindrop
This is not working with style .Alert. Most likely Apple does not foresee the modification of alerts.Yvor
Can we at least change the font and title color? Apple should atleast allowed us to do simple customization rather than using uiview that would function like an alertview or actionsheet.Choe
Yes, part of the purpose of GUI (graphical) is to make it clear and obvious sometimes by color, such as when one is about to Delete something, the color red is used to indicate, you are about to do something with potential consequences. Some of apples choices since Steve Job's passing do not seem wise.Cerecloth
@Cerecloth the iOS SDK has never allowed you to customize action sheets or alerts colors from version 1. Doesn't have anything to do with the late Mr. Jobs. They want a consistent experience. If you want something more flexible, you'll have to make it yourself.Geodesy
DiscDev, thanks, is it possible to change the individual UIAlertAction button different color?Savaii
@Savaii doubtful. Apple doesn't want you to customize alerts/actionsheets. They suggest you make your own if you want a custom look and feel. There are lots of projects on github for this, go have a look there.Geodesy
Setting the tintColor works well, but the gap between Default- and Cancel-Style-Items is than missing :(Soso
I had to set actionSheetController.view.tintColor = [UIColor blackColor]; again in the completion block to have not flicker the color after tapping on the buttons!Fiscus
A
10

Ok, I ran into the same problem but I think I have found a solution:

The appropriate way should be like this and I guess it works in iOS7:

[[UIButton appearanceWhenContainedIn:[UIActionSheet class], nil] setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];

But it will not work in iOS8 due to the fact that the ActionSheets "buttons" is now based on a UICollectionView. So after some digging around I got this to work instead:

[[UICollectionView appearanceWhenContainedIn:[UIAlertController class], nil] setTintColor:[UIColor blueColor]];
Agram answered 30/9, 2014 at 14:42 Comment(4)
Am I the only sees that this changes color for all buttons except for Cancel button?Natality
This will definitely have unintended side effects and is not advised. Changing the tint color for all UICollectionViews inside UIAlertController is fragile and relies on the view hierarchy Apple has chosen for the current version of iOS. As you can see from this answer, they changed the view hierarchy from iOS 7-> iOS 8, what's to keep them from doing it again in iOS 9? This will surely require updating in the future and is not advised.Geodesy
@friedegg-bacon-sandwich i'm getting everything in tint color except the cancel button as well. looks extremely stupid. do you know how to set the cancel button to tint color as well?Were
@friedegg-bacon-sandwich Did anybody ever solve the stubborn cancel button issue?Myoglobin
E
9

I'm using it.

[[UIView appearanceWhenContainedIn:[UIAlertController class], nil] setTintColor:[UIColor blueColor]];

Add one line (AppDelegate) and works for all UIAlertController.

Eeg answered 28/2, 2015 at 19:45 Comment(1)
Best solution imo. I added a few tweaks for backwards compatibility and to get the default tint colour, which isn't UIColor.blueColor.Subclavian
C
5

I have same task and I've made this hack today, dirty, but it works

class CustomAlertViewController: UIAlertController {

    internal var cancelText: String?


    private var font: UIFont? = UIFont(name: "MuseoSansCyrl-500", size: 12)

    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.tintColor = UIColor.blackColor()
    }

    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()

        self.findLabel(self.view) //if you need ios 9 only, this can be made in viewWillAppear
    }

    func findLabel(scanView: UIView!) {
        if (scanView.subviews.count > 0) {
            for subview in scanView.subviews {
                if let label: UILabel = subview as? UILabel {

                    if (self.cancelText != nil && label.text == self.cancelText!) {
                        dispatch_async(dispatch_get_main_queue(),{
                            label.textColor = UIColor.redColor() //for ios 8.x
                            label.tintColor = UIColor.redColor() //for ios 9.x
                        })
                    }

                    if (self.font != nil) {
                        label.font = self.font
                    }
                }

                self.findLabel(subview)
            }
        }
    }

}
Classical answered 26/10, 2015 at 15:47 Comment(1)
this answer is the best.Drysalter
S
3

Changing the tintColor of window worked for me.

In the - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions method

write this:

[self.window setTintColor:[UIColor redColor]];

This changed the font color of all UIActionSheet objects.

Spelt answered 21/1, 2015 at 15:1 Comment(1)
While this does not answer OP's question, it just solved my specific issue. Thanks!Brittney
S
3

For iOS 7 backwards compatibility, and to collect the proper default tint colour (that Apple may well change in future versions), I use this. Thanks to the answers about default tint and to Lucas's answer above.

    const Class alertControllerClass = NSClassFromString(@"UIAlertController");
    if(alertControllerClass)
    {
        UIColor *defaultTintColour = UIView.new.tintColor;
        [[UIView appearanceWhenContainedIn: alertControllerClass, nil] setTintColor: defaultTintColour];
    }

Caution though – you need to ensure that you use this before you start setting the global tint otherwise the UIView.new.tintColor will just give you the current tint you have set up.

Subclavian answered 25/3, 2015 at 17:47 Comment(3)
This doesn't work for iPads on iOS 9, for some reason. Poo. :-(Subclavian
[self.window setTintColor:[UIColor whateverColor]] is the only thing I've found that works in iOS 8 and 9Mealworm
@Mealworm I'll look at that – I've already set this to something else for some reason, but perhaps I can achieve that elsewhere…Subclavian
W
3

Swift 4

    let alert =  UIAlertController(title: "title", message: "message", preferredStyle: .alert)
    alert.view.tintColor = UIColor.black
    self.present(alert, animated: true, completion: nil)
Warmonger answered 28/1, 2019 at 16:12 Comment(0)
O
2

For Swift you can do like this

    let alertAction = UIAlertAction(title: "XXX", style: .default) { (action) in

     }

    alertAction.setValue(UIColor.red, forKey: "titleTextColor")
Odetteodeum answered 7/2, 2019 at 16:13 Comment(1)
This has been answered above already. Also it will be rejected as already pointed out.Experimentalize
C
0
let alert = UIAlertController(title: "Delete Note", message: "Are you sure to delete this note?", preferredStyle: .alert)
alert.view.tintColor = UIColor.green
Candie answered 2/2, 2023 at 12:26 Comment(1)
Your answer could be improved by adding more information on what the code does and how it helps the OP.Blackfellow

© 2022 - 2024 — McMap. All rights reserved.