32

In iOS 8, it seems that buttons on UIAlertController (specifically the action sheet type) as well as buttons on the UIActivityViewController get their color from the main window's tintColor.

How can I change the color of the button text? I've tried using the appearance proxy like this:

[[UIButton appearanceWhenContainedIn:[UIActivityViewController class], nil] setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];

But it has no effect. My window's tintColor is white, so the text on the UIActivityViewController buttons is also white, and it cannot be seen. Changing my window's tintColor resolves this issue, but it messes up the rest of the app.

See the screenshot of my UIActivityViewController with a white cancel button with white text on the bottom:

UIActivityViewController with white Cancel button text

The same thing applies to UIActionSheet (yes, I know it's deprecated) and UIAlertController with the actionSheet type.

How can I make the text on these windows readable without changing the tintColor of the entire app?? Thanks in advance!

DiscDev
  • 38,652
  • 20
  • 117
  • 133
  • Why not just change your Window's tint color from white? I guess I don't know enough about the window tint color to know what all it does – beebcon Oct 25 '17 at 18:20

6 Answers6

30

In addition to the global tint color defined for your application, each view controller allows you to override the tint color for just that controller. In this case your best bet would be to set the tintColor on your UIActivityViewController after initializing but before presenting.

UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:activities];

//Set the tint color on just the activity controller as needed here before presenting
[activityController.view setTintColor:[UIColor blueColor]];

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

If you are doing this a lot in your app you could use a subclass or a category to avoid code duplication.

jlichti
  • 867
  • 9
  • 7
  • 2
    +1 & thanks -- I'm just here to add some magic keywords which might help other people who are having the same problems like me... I was searching for "invisible cancel" or "blank cancel" or "white cancel". It took quite a bit of searching to find this very useful Q&A. – Michael Dautermann Nov 19 '14 at 07:22
  • this doesn't work well with iOS 7, I get a transparent background in the UIActivityViewController when I try to change the view's tintColor – Halpo May 06 '15 at 13:40
21

This worked for me with the UIAlertController.

[[UIView appearanceWhenContainedIn:[UIAlertController class], nil] setTintColor:[UIColor blackColor]];
AndreasZ
  • 1,060
  • 13
  • 16
  • 3
    This will likely have unintended side effects since you're changing the tint color of every single view inside of a UIAlertController. If they change the view hierarchy in the future, this will break for sure. – DiscDev Oct 28 '14 at 13:46
  • This worked for me (iOS 8.4): `[[UIView appearanceWhenContainedIn: [UIActivityViewController class], nil] setTintColor: [UIColor blackColor]];` which targets the Activity Controller better. – Leslie Godwin Jul 07 '15 at 06:36
  • 6
    This should be the accepted answer, as it achieves exactly what you want to do: set the tint color of only certain view controllers (like alert controllers or activity controllers) to something other than your main tint color. If it doesn't work in iOS 9 then we should file a radar because that is a bug. This is exactly what appearance proxies are designed for. – Cory Imdieke Aug 20 '15 at 17:27
  • 1
    Because this does not work in iOS 9, here is a workaround for setting the `tintColor` of a `UIAlertController` button: http://stackoverflow.com/a/32636878/4376309 – peacetype Oct 30 '15 at 20:11
  • The accepted answer works great in iOS 9 - this answer is brittle/hacky and it appears to have many unintended side effects, especially since it tints ALL UIViews contained in a UIAlertController. Use this solution at your own risk. – DiscDev Jun 07 '16 at 17:08
4

iOS 11

        let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
        activityVC.popoverPresentationController?.sourceView = self.view

        //Set your activity view controller's appearance
        UIButton.appearance().tintColor = .blue

        //Set back to default UIButton appearance
        self.present(activityVC, animated: true, completion: {
            DispatchQueue.main.async {
                UIButton.appearance().tintColor = nil
            }
        })
belebeich
  • 391
  • 3
  • 8
  • This messed up other buttons in my app that were using a custom tint color. – kmell96 Apr 18 '18 at 01:11
  • you should set your color instead of nil – belebeich Apr 18 '18 at 09:46
  • Not all of my buttons use the same tint color so I set the tint color of each button individually; your code was the only place where I set `UIButton.appearance().tintColor`. I was able to fix the issue by moving all my setting of tint color from initializers to `viewWillAppear`, then your solution worked. Super hacky but effective. – kmell96 Apr 18 '18 at 18:27
2

In iOS 9 I was able to fix this by tinting the view that presented the UIActivityViewController. Unfortunately, in iOS 10/Xcode 8 this stopped working for me. I was trying to tint a Sharing panel so that the cancel button would not have white, invisible looking text.

The only thing that I found to work in iOS 10 is UIButton.appearance().tintColor = UIColor.red. You can set this globally in app delegate (but this tints your nav bar buttons etc too, so you then have to go and tint them another color manually). You can also set this locally in a view, but because it is actually a global theme that gets applied to all Button types, you have to then set it back to another color after if you don't want the next views to pick it up.

Thus I was able to get it working as a tint to just my ActivityController buttons in a 'hackish' way by adding the line above with my tint color after I initialized the UIActivityViewController but before I presented it. And then I set the tint back to my preferred color (white) in the completion handler of the ActivityController presentation function.

ex: // image to share let image = UIImage(named: "Image")

    // set up activity view controller
    let imageToShare = [ image! ]
    let activityViewController = UIActivityViewController(activityItems: imageToShare, applicationActivities: nil)
    activityViewController.popoverPresentationController?.sourceView = self.view 
    UIButton.appearance().tintColor = UIColor.red

    // present the view controller
    self.present(activityViewController, animated: true, completion: {
        DispatchQueue.main.async {
            UIButton.appearance().tintColor = UIColor.white
        }
    })
Natalia
  • 1,308
  • 16
  • 23
1

WORKED FOR ME - backup current tint first

//COLCSocialManager.showShareActivityViewController(fromVC: aViewController)
    class func showShareActivityViewController(fromVC vc: UIViewController){


        let textToShare = "TAXI. New iOS app for tourists and cabbies. Check it out its free."
        let linkToShare = "http://buff.ly/dddd"

        //on FB the link is converted
        let activityItems: [Any] = [ textToShare, linkToShare ]

        let activityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)
        activityViewController.popoverPresentationController?.sourceView = vc.view // so that iPads won't crash

        // exclude some activity types from the list (optional)
        //activityViewController.excludedActivityTypes = [ UIActivityType.airDrop, UIActivityType.postToFacebook ]

        let buttonTintBackup = UIButton.appearance().tintColor

        UIButton.appearance().tintColor = UIColor.red

        // present the view controller
        vc.present(activityViewController, animated: true) {
            UIButton.appearance().tintColor = buttonTintBackup
        }

    }
brian.clear
  • 5,277
  • 2
  • 41
  • 62
  • Only works if all buttons that use a custom tint color set the tint with UIButton.appearance() and not the tint of the view itself. Otherwise, backing up that appearance doesn't fix the issue. – kmell96 Apr 18 '18 at 01:13
0

Elegant solution using with completion handler for the UIActivityController.

    let barTintColor = UINavigationBar.appearance().barTintColor
    let bTintColour = UINavigationBar.appearance().tintColor

    UINavigationBar.appearance().barTintColor = UIColor.white
    UINavigationBar.appearance().tintColor = UIColor.darkGray

    activityViewController.completionWithItemsHandler = {(activityType: UIActivityType?, completed: Bool, returnedItems: [Any]?, error: Error?) in
        UINavigationBar.appearance().barTintColor = barTintColor
        UINavigationBar.appearance().tintColor =  bTintColour
    }
Prakash
  • 812
  • 6
  • 16