Text color in UIMenuController affected by UIButton appearance setting - uibutton

I've observed following:
By setting the Titlecolor of a UIButton with appearance, the UIMenuItems in a UIMenuController of a UITextView are getting the same color.
Code in applicationDidFinishLaunching:
[[UIButton appearance] setTitleColor:[UIColor greenColor] forState:UIControlStateNormal];
My question:
Is there a way to suppress it
or
give a UIMenuItems another color?
What i have tried:
With appearanceWhenContainedIn UITextview
I've tried to set the appearance for buttons contained in TextViews with
[UIButton appearanceWhenContainedIn:[UITextView class], nil]
But this obviously didn't work since the UIMenuController is not inside the TextView.
With appearanceWhenContainedIn UIMenuController/UIMenuItem
Is not possible, since both are not implementing the UIAppearanceContainer protocol.

I found 2 ways to fix this issue.
Here is a screenshot of the result of the following solutions :
First solution
The UIMenuController is not contained in the View Controller views hierarchy. You can thus define your UIButton color that way (instead of setting the global Button appearance) :
Swift :
UIButton.appearanceWhenContainedInInstancesOfClasses([UIViewController.self]).setTitleColor(UIColor.redColor(), forState: UIControlState.Normal)
Objective-C :
[[UIButton appearanceWhenContainedInInstancesOfClasses:#[UIViewController.class]] setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
That solution works for most of the cases. But if you use the delete button or actions button of Table View Cells it will also take the set color and you won't be able to change that color through appearance proxy.
Second solution (my preferred one)
The second solution uses directly the private UIButton subclass class name used by Apple in the Menu Controller.
I would never recommend to access a private Apple class (and furthermore through its name), but in that specific Menu Controller color customization case I think that's the best solution. It lets you define the clean way your view appearances.
Swift :
Define your global Button title color appearance :
UIButton.appearance().setTitleColor(UIColor.redColor(), forState: UIControlState.Normal)
Specific exception for the MenuController :
(NSClassFromString("UICalloutBarButton")! as! UIButton.Type).appearance().setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
Objective-C :
Define your global Button title color appearance :
[[UIButton appearance] setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
Specific exception for the MenuController :
[[NSClassFromString(#"UICalloutBarButton") appearance] setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];

Related

How do I make UIBarButton Work as Switch Given that UIBarButton Doesn't have Selected Property

With normal button you can do
btn.selected = !btn.selected.
How would I pull that out with UIBarButton?
You can create UIBarButtonItem with the custom view
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setImage:normalImage forState:UIControlStateNormal];
[button setImage:selectedImage forState:UIControlStateSelected];
[button addTarget:self action:#selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:button];
Then
-(void)btnClick:(id)sender{
UIBarButtonItem *item = (UIBarButtonItem *)sender;
UIButton *button = (UIButton *)item.customView;
[button setIsSelected:YES];
}
You can use a custom Button inside UIBarItem, remain one just do with you button.
UIBarButtonItem *barButton = [[UIBarButtonItem alloc] initWithCustomView:self.yourButton]
[self.navigationItem setRightBarButtonItem:barButton];
Then:
self.yourButton.select = !self.yourButton.select;
Idea 1. If you are creating your interface in IB, try dragging a standard UIButton object into the UIToolbar. This should encapsulate the UIButton inside a UIBarButton.
Set the UIBarButton object to be plain.
Create outlets to everything as usual.
Then you can use the standard button along with all it's lovely standard things like selected state in the toolbar.
Idea 2. I've pretty much given up on using toolbars as the controls are inflexible as you're finding. Now I just replace instances of UIToolbar with UIViews and do the small amount if code it needs to manage rotation, resizing etc... I've found it more flexible and let's me includes other controls more easily.
It is not possible to have the selected property through UIBarButtonItem straight away. But you can achieve this by placing the UIButton and customizing it like a UIBarbutton. This link will be more useful to you...How do I programmatically get the state of UIBarButtonItems?

How to set UIButton's Highlight Tint color programmatically?

There is a Highlight Tint option in Interface Builder for UIButton. Is it possible to change it programmatically for all UIButton in iOS 5....using some kind of appearance protocol thing or some other workaround?
You can set it as
[button setTintColor:[UIColor grayColor]];
This is equivalent to hightlight tint option in IB and is applied only for highlighted state.
Update:
In order to implement this for all the buttons in app, use this:
[[UIButton appearance] setTintColor:[UIColor orangeColor]];
It will set for all the UIButton which you are going to use in your app.
Check this for more details on UIAppearance protocol.

How to set appearance for a UIButton without affecting UIBarButtonItems?

Using the following code to customize regular UIButtons also affects UIBarButtonItems and clear buttons in text fields.
[[UIButton appearance] setBackgroundImage:greenButtonImage forState:UIControlStateNormal];
I do not wish to customize the latter elements at all, only regular round rect buttons. I realize using appearanceWhenContainedIn: could be used to set a custom appearance for UIBarButtonItems and UITextField, but i wish for these buttons to remain standard. Subclassing is not an option here as it should not be required for such a simple task.
There is a similar question, but it does not address the issue. Why does -[[UIButton appearance] setBackgroundImage] affect the initial appearance of UIBarItem objects and how do you correct it?
One solution I've used before is to nil out the "backgroundImage" property for UIButtons contained inside of a UINavigationBar:
[[UIButton appearanceWhenContainedIn:[UINavigationBar class], nil] setBackgroundImage:nil forState:UIControlStateNormal];
This should allow you to customize UIButtons in other cases, without touching the ones inside a UIBarButtonItem in the UINavigationBar.

Custom UIButton rounded corners

I'm customizing UINavigationBar and have to set a custom background image to the navigation buttons. This is done this way:
for (UIView *view in self.navigationController.navigationBar.subviews) {
if ([[[view class] description] isEqualToString:#"UINavigationButton"]) {
UINavigationButton *button = {(UINavigationButton *)view};
[button setBackgroundImage:[UIImage imageNamed:#"bar_button.png"] forState:UIControlStateNormal];
[button setBackgroundImage:[UIImage imageNamed:#"bar_button_black.png"] forState:UIControlStateSelected];
[button setBackgroundImage:[UIImage imageNamed:#"bar_button_black.png"] forState:UIControlStateHighlighted];
}
}
Won't this be rejected by Apple?
How can I make UIButton/UIView corners to be rounded?
A UIView object has a property named layer (CALayer) and a layer has a cornerRadius property.
Create your custom buttons as normal UIButtons, with your custom image. Then create UIBarButtonItems with your new UIButton as a custom view (you can see how to do this in the UIBarButtonItem class reference).
Then, set your view controller's navigationItem to have your new UIBarButtonItems as the leftButtonItem, rightButtonItem and so on.
Instead of this do like this.Take a UIButton and then add it to the navigation buttons.

Change Round Rect Button background color on StateHighlighted

I'm trying to change the background color of a button when it's selected and don't want to use an image.
[mBtn setBackgroundColor:[UIColor grayColor] forState:UIControlStateHighlighted];
Any thoughts?
I'm replying to this old thread because it pops up consistently in searches for a solution to this problem and I have seen no solution elsewhere. It is truly annoying that setTintColor only applies to the highlighted state of a UIButton. Six months ago, it was equally annoying that it applied only to iOS 5, but that will hopefully be less of an issue going forward. With that in mind, I've drawn upon and combined a number of community suggestions to composite a general purpose solution to tinting a group of buttons in their normal state.
The method below accepts an NSArray of UIButtons and a set of color specifications as input. It applies the color specifications to one button using setTintColor, renders the result to a UIImage, and applies that image as the background image of the entire set of buttons. This avoids the need to create discrete image files for button colors. Also, it does so using a stretchable image so that it may work with a collection of buttons of different sizes (though note that it assumes the default corner rounding factors of UIButton). I hope you'll find it useful for iOS 5 targets.
- (void) setColorOfButtons:(NSArray*)buttons red:(float)red green:(float)green blue:(float)blue alpha:(float)alpha {
if (buttons.count == 0) {
return;
}
// get the first button
NSEnumerator* buttonEnum = [buttons objectEnumerator];
UIButton* button = (UIButton*)[buttonEnum nextObject];
// set the button's highlight color
[button setTintColor:[UIColor colorWithRed:red/255.9999f green:green/255.9999f blue:blue/255.9999f alpha:alpha]];
// clear any existing background image
[button setBackgroundImage:nil forState:UIControlStateNormal];
// place the button into highlighted state with no title
BOOL wasHighlighted = button.highlighted;
NSString* savedTitle = [button titleForState:UIControlStateNormal];
[button setTitle:nil forState:UIControlStateNormal];
[button setHighlighted:YES];
// render the highlighted state of the button into an image
UIGraphicsBeginImageContext(button.layer.frame.size);
CGContextRef graphicsContext = UIGraphicsGetCurrentContext();
[button.layer renderInContext:graphicsContext];
UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
UIImage* stretchableImage = [image stretchableImageWithLeftCapWidth:12 topCapHeight:0];
UIGraphicsEndImageContext();
// restore the button's state and title
[button setHighlighted:wasHighlighted];
[button setTitle:savedTitle forState:UIControlStateNormal];
// set background image of all buttons
do {
[button setBackgroundImage:stretchableImage forState:UIControlStateNormal];
} while (button = (UIButton*)[buttonEnum nextObject]);
}
[mBtn setTintColor:[UIColor grayColor]];
This only effects the highlighted state, so I believe that this is what you're looking for.
You can also set it from Interface Builder, from the Highlight Tint drop-down menu.
Just for people that will land here like I did when searching for changing background colors for highlighted state...
I ended up with an UIButton subclass that has a property for backgroundHighlightColor and tracks highlighting through KVO. Here's the link to GitHub: SOHighlightButton
You should be able to adapt it to any other scenario if you need more / other properties ot the UIButton to change if highlighted.
There is no method like this, setBackgroundColor: forState:
Check documentation. you need to use image.