I have set a custom tint color for a UINavigationBar (within a UINavigationController) which, in turn, sets an appropriate matching color for the UIBarButtonItems which are inserted into the UINavigationBar. However, when I select a UIBarButtonItem the button turns into (presumably) the highlighted state and presents a different color, which looks quite a bit out and does not nicely match the tint color. Is there a way to change this highlighted state color to a custom color?
Ideally, I would like to just create a category on UIBarButtonItem which changes the highlighted color for all instances of UIBarButtonItem, as this would avoid the need to explicitly subclass UIBarButtonItems and then change every reference in my app to use the subclass (which will be tricky, as I am using some third-party libraries which just use UIBarButtonItem and I don't want to go messing with their implementation).
Any help would be greatly appreciated.
From what I remember from facing a similar issue, UINavigationBar will just take the tintColor and make it darker for the UIBarButtonItem (unless the style is set to BarStyleBlack, in which case it makes it a dull gray).
To do what you ask, I would create a custom UIButton with background images for the different control states that match your color scheme, then use this UIButton as the view for a custom UIBarButtonItem.
UIButton *customButton = [UIButton buttonWithType:...];
//normal_button.png and selected_button.png need to be created by you
[customButton setBackgroundImage: [UIImage imageNamed:#"normal_button.png"] forState:UIControlStateNormal];
[customButton setBackgroundImage: [UIImage imageNamed:#"selected_button.png"] forState:UIControlStateSelected];
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView: customButton];
If you want to try and encapsulate this, you could always create a factory or a custom init method on UIBarButtonItem (via a category) and use the above code (with slight modifications).
I am aware that I am not fully addressing your second point on just overriding the control state with a category. I don't know what method to override in UIBarButtonItem to do such a thing, but you may be able to accomplish what you want via method swizzling (http://cocoadev.com/index.pl?MethodSwizzling) once you find out which method you want to exchange.
I should note that I've only ever used swizzling for testing/debugging.
If you're using Interface Builder, drag and drop an UIButton to the navigation's bar right side, and it gets in as a right navigation bar button item. Then, configure different tints for different states of the button, and you're done.
Works in Xcode 10 and Swift 4.
Related
When customizing the appearance of UIButton using the class proxy UIBarItems seem to initially take on the custom properties set for UIButton.
Starting with the default Master/Detail project using Core Data. Customize the appearance of UIButton in the AppDelegate and run the app. Click the Edit button, then the Done button in the navigation bar for the MasterViewController and watch the customization go away.
Custom appearance code in [AppDelegate application:didFinishLaunchingWithOptions]:
UIImage *customBackground = [[UIImage imageNamed:#"yourcustomimage.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(5,5,5,5)];
[[UIButton appearance] setBackgroundImage:customBackground forState:UIControlStateNormal];
All UIBarButtonItems initialize with custom background
When the Edit button is replaced by the Done button, it correctly does not have the customized background.
A similar question asks how to customize the Done button. I'm concerned why this is happening at all to UIBarItem objects, which do not inherit from UIButton, and would like to know how to correct it.
I suspect the proxy inheritance and the supported properties, but I don't know how to correct for it. Any suggestions?
My suggestion would be to reset backgroundImage to nil when contained in UINavigationBar:
[[UIButton appearance] setBackgroundImage:customBackground forState:UIControlStateNormal];
[[UIButton appearanceWhenContainedIn:[UINavigationBar class], nil] setBackgroundImage:nil forState:UIControlStateNormal];
I've had trouble getting this to work, nowhere have I seen a working example on the web. Now offering bounty on this as its making me crazy. It should be easy, but that doesn't seem to be the case.
I'd like my buttons on my UINavigationBar to be semi-transparent such that they allow the background of whatever is on the UINavigationBar to show through. This effect is seen in many applications, image examples below. You can do this by setting a custom background on the item, which i think is an unacceptable solution because it requires that you prepare images beforehand, and they won't be adaptable for variable buttons etc. They will not look like Apple UI and I don't believe there is a reason to do this either, UIKit is already drawing the background for these buttons, we just need to change it. The correct solution uses the bar items and views generated by Apple's apis.
UIBarButtonItem is not a UIView subclass. When you create one and add it to a UINavigationBar, some code somewhere in the framework draws a view for it. The framework methods seem to resist anything related to allowing transparency of the bar items, such as the tintColor property.
For example, this does NOT work:
UINavigationItem *item = [[UINavigationItem alloc] init];
UIBarButtonItem *editButton = [[UIBarButtonItem alloc] initWithTitle:#"SUCKS" style:UIBarButtonItemStyleBordered target:self action:#selector(whatever:)];
editButton.tintColor = [UIColor colorWithWhite:0.4 alpha:0.3];
item.leftBarButtonItem = editButton;
Nothing I do will make UINavigationBar allow semi-transparency for its bar items. I believe at runtime we need to:
Get the image for the bar item
Mask it for transparency
Set the new image on the bar item
But I haven't been able to get the image at runtime or mask it properly. How do you do this?
Create a custom uiview and draw a semi-transparent black rectangle in it and use that view with initWithCustomView.
see
and
Failing that, you may have to use an image (png). e.g. a 1x1 black pixel png with 30% opacity.You could then initWithImage.
EDIT: I have had this second approach working using:
buttonThree = [[UIBarButtonItem alloc] initWithTitle:#" sort button " style:UIBarButtonItemStyleBordered target:self action:#selector(sortMethod)];
UIImage *thebgUIimage = [UIImage imageNamed:#"semi.png"];
[buttonThree setBackgroundImage:thebgUIimage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
This results in a button that has a transparent background image that the navbar background image shows through. However, you would need to create an image with the rounded corners on and so need an image for each button width. Also I found this thread after trying the above
A brilliant hack is to use the UISegmentedControl with a single segment (as a button) and set its tint color. Have a look at http://charles.lescampeurs.org/2011/02/10/tint-color-uibutton-and-uibarbuttonitem. I have personally implemented this. Feel free to ask any questions.
Instead of searching for code and breaking your head, my suggestion is just to have transparent image which has just border similar to button (add shadow if necessary), create a button of custom type, add the transparent background image to it and you can text as you want. From this custom button, create your bar button item accordingly.
If you're targeting for iOS 5, you can set the background image of the button.
[_button setBackgroundImage:#"image" forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
Note that you'll need to set background images for state UIControlSateSelected and again for both control states for barMetrics: UIBarMetricsLandscape, if your application allows landscape orientation.
Note again this is an iOS 5 feature.
I believe your answer is here: http://sebastiancelis.com/2009/12/21/adding-background-image-uinavigationbar/
I currently work on a small application in which I have several UIButtons. Each of them has an UIImageView beneath it. At the moment, I associate each UIButton with each UIImageView (all are named via an IBOutlet - UIButton and UIImageView). When I press a button, the underlying image changes. I would like to know if it's possible (and how) to create a button which contains an underlying UIImage (not a UIButton image or background image), a sort of new object.
This image is slightly larger than the associated UIButton, like the apple calculator basic apps, and this image changes when I press the button.
I've tried several solutions (certainly incomplete) and I'm beginning to despair.
My current solution is functional but I do find it not particularly elegant.
UIButton has both image and backgroundImage as its properties.
To achieve what you are looking for, I would actually recommend you to stick to just a UIButton, and then using contentInset to position the image over the backgroundImage so it creates the effect I think you are looking for. This should be quite easy in interface builder...
you can make an invisible button and behind it make the image..
This will give you what you want but should be avoided at cost...
Stick to UIButton..
I believe even in calculator app they are only UIButtons and nothing else..
they have been coded to been momentary selected ..so that's why you see them kind of changing highlight for a small fraction and each button have been coded to perform specific function(+ - / equal .)
Update : i might be in doubt but if you asked for a button to have an image view inside it..
then here is the answer.
Make UIbutton. Make an ImageView and then call [theButton.view addSubview:ImageView];
Since both UIbutton and UIImage view inherit from UIView.. you can add as many subviews to them..that is inside them
If I understood your question correct then you may try the following:
UIButton *button = [UIButton alloc]init];
[button setImage:buttonImage forState:UIControlStateNormal]; when button not pressed
[button setImage:buttonImage forState:UIControlStateSelected]; when button tapped
[button release];
I use Three20 to create UIBarButtonItem as shown in this StackOverFlow question:
Custom UIBarButtonItem with quartz
now I what that UIBarButtonItem have no glossy effect and can have different color (light color and dark color).
Do you know how to do it?
UPDATE:
and I would like to do it without using images.
You can always use initWithCustomView on UIBarButtonItem and using it you can basically put in that view what ever you want - TTButton, UIButton, custom UIView, etc...
The default background color is black. How can I change the color, similar to tintColor for navigation bars?
A possible solution to change the text color consists in using the appearance proxy of the UIButton inside the UIMenuController. The thing is it uses directly the private UIButton subclass 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
(NSClassFromString("UICalloutBarButton")! as! UIButton.Type).appearance().setTitleColor(UIColor.redColor(), forState: UIControlState.Normal)
Objective-C
[[NSClassFromString(#"UICalloutBarButton") appearance] setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
I'm pretty sure this is not possible. You may be able to work something out if you subclass it.
EDIT: I took a look at the UIMenuController.h file and there don't seem to be any obvious ways to change the color. It is a subclass of NSObject if that helps you. Also, if you take a look at how people subclass UITabBarController to change it's color you may be able to work out a similar solution.
You can set the background color of UIMenuController like this -
Objective-C
[[NSClassFromString(#"UICalloutBarButton") appearance] setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:0.8]];
Make sure that you use a color with transparency/alpha, otherwise it will throw an error.