I want to change the UISearchBar's Cancel button to one that only has an image, and no text. Here's where I got to so far from original behaviour
to this
A step in the right direction, but the problem is the button is too wide. When I debug the view, I can see that it has button label insets of 11 points on left and right. Does anyone know how to make the button fit the content size? The image is square.
Here's my code for customising the button:
UIBarButtonItem *barButtonAppearanceInSearchBar;
if (IOS9) {
barButtonAppearanceInSearchBar = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:#[[UISearchBar class]]];
} else {
barButtonAppearanceInSearchBar = [UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class], nil];
}
barButtonAppearanceInSearchBar.image = [UIImage imageNamed:#"Close"];
barButtonAppearanceInSearchBar.title = nil;
Another weird issue is that when I dismiss the search bar and activate it again, the button image turns dark (it's still there, I can see it when debugging the views), so it looks like this
Any idea how to keep the icon white? I tried this method below, but without results:
- (void)willPresentSearchController:(UISearchController *)searchController {
searchController.searchBar.tintColor = [UIColor whiteColor];
}
Use image rendering and tint color.
barButtonAppearanceInSearchBar.image = [[UIImage imageNamed:#"Close"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
barButtonAppearanceInSearchBar.tintColor = [UIColor whiteColor];
barButtonAppearanceInSearchBar.title = nil;
Here's the Swift 4.1 Version of #jamesBlake 's answer:
func setUpSearchBar() {
let barButtonAppearanceInSearchBar: UIBarButtonItem?
barButtonAppearanceInSearchBar = UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self])
barButtonAppearanceInSearchBar?.image = UIImage(named: "Home.png")?.withRenderingMode(.alwaysTemplate)
barButtonAppearanceInSearchBar?.tintColor = UIColor.white
barButtonAppearanceInSearchBar?.title = nil
}
Related
How come the icon info.png stays blue and don't comes with the original color of that image? I am using the following code below:
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"info.png"]
style:UIBarButtonItemStylePlain
target:self
action:#selector(info:)];
By default, image in UINavigationBar's bar button items is rendered using template mode. You can set it to original.
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[[UIImage imageNamed:#"info.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]
style:UIBarButtonItemStylePlain
target:self
action:#selector(info:)];
Swift 3:
let image : UIImage? = UIImage.init(named: "heart.png")!.withRenderingMode(.alwaysOriginal)
I know this is too late to answer this question but I see there is a very simple way to solve this issue instead of doing some changes in the code
using Xcode
Go to the Assets --Select Image --- check Render as and select Original image instead of default property .
You can it from assets as well. Go to Assets.xcassets >> Select the image that is being used as barbutton item image. Tap on attribute inspector in right side panel. Choose render as to orignial image. It will be default earlier. You will now see colored image.
Swift 4:
let image = UIImage(named: "imageName")?.withRenderingMode(.alwaysOriginal)
navigationItem.leftBarButtonItem = UIBarButtonItem(image: image, style: .plain, target: self, action: #selector(leftBarButtonPressed))
For Swift 2.1+ it would look like this:
let image : UIImage? = UIImage(named:"myImage.png")!.imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal)
or simply
let image : UIImage? = UIImage(named:"myImage.png")!.imageWithRenderingMode(.AlwaysOriginal)
Because the color of barButtonItems in your app is related to the tintColor property on the application's window.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window.tintColor = [UIColor redColor];
return YES;
}
Ok, got it... I set the image to it's original state first.
UIImage *image = [[UIImage imageNamed:#"info.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithImage:image
style:UIBarButtonItemStylePlain
target:self
action:#selector(info:)];
Change the bar button item tint color from the storyboard. Or color from the image in storyboard.
The color should be your expected color as hex or rgb.
I am trying to find a way to change the tint color of the backBarButtonItem based on the scroll position. In the example below, the button should be yellow by default, but then at a certain threshold it should change to red.
Although using breakpoints I can see the code triggering in each block, but unfortunately backBarButtonItem never changes to red and always remains yellow. Any suggestions on why this might be the case? I'm assuming that you might not be able to change the back button in the navigation bar once it's already set.
CGFloat totalHeight = CGRectGetMaxY(self.frame);
CGFloat barHeight = CGRectGetHeight(self.frame);
CGFloat offsetHeight = (self.scrollview.contentOffset.y - self.scrollViewMinimumOffset) + totalHeight;
offsetHeight = MAX(offsetHeight, 0.0f);
offsetHeight = MIN(offsetHeight, totalHeight);
if (offsetHeight > barHeight * 1.0f) {
[self.backBarButtonItem setTintColor:[UIColor redColor]];
} else {
[self.backBarButtonItem setTintColor:[UIColor yellowColor]];
}
Let me provide the following example that can help you figure out or gain some ideas to better address the issue.
So in the storyboard (can be done programmatically), I have the following scenario:
That backBarButtonItem is actually 1stVC button in the NavigationBar.
In order to change the color of backBarButtonItem, you may implement the following code (or take a look):
import UIKit
class ViewController2: UIViewController {
var counter = 0 //any conditions you want to play with
override func viewDidLoad() {
super.viewDidLoad()
var color: UIColor = UIColor.purple //or yellow, by default
if(counter == 0){
color = UIColor.red
}
self.navigationController?.navigationBar.tintColor = color
}
}
It is done in the viewDidLoad() method of ViewController2 so that it can get configured as soon as this ViewController is opened.
Here, I just used counter variable as a simple example to create some condition based on which the color of backBarButtonItem should be changed. In your case, you have another condition.
So this is the output:
What I'd like to do is alter the height of the back button. However, as I understand it, the only option to alter is width. So, I thought I'd create a custom back button with my own, smaller, image. Now I've done this using the viewDidLoad method with the code below:
//Setup navigation bar
navigationController?.navigationItem.backBarButtonItem = UIBarButtonItem(image:UIImage(named:"back_arrow.png"), style:UIBarButtonItemStyle.Plain, target:nil, action:nil)
navigationController?.navigationItem.backBarButtonItem!.title = ""
However, the back button remains blue, large, and has the title 'Back'. How can I get this code to work properly? The debugger says it is running, but it is not changing anything.
I'm going to show you how to do this in the entire app, not just one page.
To change the default image of the back button, put the following in your app delegate didFinishLaunchingWithOptions::
Swift:
let backArrowImage = UIImage(named: "customImage")
let renderedImage = backArrowImage?.imageWithRenderingMode(.AlwaysOriginal)
UINavigationBar.appearance().backIndicatorImage = renderedImage
UINavigationBar.appearance().backIndicatorTransitionMaskImage = renderedImage
Obj-c:"
UIImage *backArrowImage = [UIImage imageNamed:#"customImage"];
UIImage *renderedImage = [backArrowImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
[UINavigationBar appearance].backIndicatorImage = renderedImage;
[UINavigationBar appearance].backIndicatorTransitionMaskImage = renderedImage;
To remove the "Back" text from the button, add this category to your AppDelegate.m file (or your own category):
Not sure how to do this in Swift yet, so here's the Obj-c version:
#implementation UINavigationItem (LuxeCustomization)
/**
Removes text from all default back buttons so only the arrow or custom image shows up
*/
-(UIBarButtonItem *)backBarButtonItem
{
return [[UIBarButtonItem alloc] initWithTitle:#"" style:UIBarButtonItemStylePlain target:nil action:nil];
}
#end
For color you have to set the tint color on navBar, also you can set navigationItem.backBarButtonItem to nil and use leftbarButtonItem with custom button image.
One of the screens in my app shows a preview of a local image and I have an action button in the top left corner that I'm using to present document interaction options:
- (IBAction)actionButtonTapped:(id)sender {
self.interactionController = [UIDocumentInteractionController interactionControllerWithURL:self.attachmentLocalUrl];
self.interactionController.delegate = self;
[self.interactionController presentOptionsMenuFromRect:self.view.frame inView:self.view animated:YES];
}
This works well as it shows an action sheet with a list of options, including email to send the attachment by email. When I click the email button, it displays a preview of the email message with my image in it. But there is one thing that doesn't work. I have customized the appearance of my app so that the navigation bar has the same colors throughout the app. Here is the code I run first in my app delegate's didFinishLaunchingWithOptions:
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
[UINavigationBar appearance].barTintColor = [UIColor blueColor];
[UINavigationBar appearance].tintColor = [UIColor whiteColor];
[UINavigationBar appearance].titleTextAttributes = #{NSForegroundColorAttributeName: [UIColor whiteColor]};
This works well for my own view controllers, but the email preview view controller displayed by UIDocumentInteractionController has its bar button items in blue instead of white. And since the other parameters are correctly applied, especially the blue background for the navigation bar, the Cancel and Send action buttons are almost invisible.
I have tried reproducing this in a simple project but I couldn't. So obviously I'm doing something in my app to interfere with the normal customization. But I can't figure out what. Any idea how I might debug that?
Can you clarify exactly what you are meaning? Is the colors on the navigation bar screwed up on the documentpicker or the mfmailcomposer? Here's some code for either though that I had to use...
If it's on the UIDocumentPicker, set this before calling present:
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)
{
[[UIBarButtonItem appearance] setTintColor:[UIColor blackColor]];
[[UINavigationBar appearance] setTintColor:[UIColor blackColor]];
}
and then change it back to the colors you had in the didPickDocument and didCancel Delegates
if it's on the MFMailcomposer controller then use this:
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)
{
[controller.navigationBar setTintColor:[UIColor blackColor]];
}
Hope this helps
I settled on the workaround to clear the customization before presenting the UIDocumentController and then restore my custom theme in viewWillAppear() of the view controller presenting the UIDocumentController.
func launchDocumentController() {
UINavigationBar.appearance().titleTextAttributes = nil
UINavigationBar.appearance().barTintColor = nil
UINavigationBar.appearance().tintColor = nil
documentController.presentOptionsMenuFromRect(self.view.frame, inView: self.view, animated: true)
}
Then
public override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
// Restore the reset bar colors
Theme.current.customizeAppearance()
}
Short of an OS update, I think this is the best 'answer' your are going to get. Sorry. (When I get a chance I will file a radar.)
In the cases where you have direct access to MFMComposeViewController setting the tint color as described above, is a good workaround.
Here is what perfectly worked for me:
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
UINavigationBar.appearance().barTintColor = Colors.redColor()
UINavigationBar.appearance().tintColor = UIColor.white
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName : UIColor.white, NSFontAttributeName: UIFont.systemFont(ofSize: 14, weight: UIFontWeightBold)]
return self
}
I am designing a Music app for iOS 7 and I want to put the "AirPlay" route selector button directly in my app. I am able to get the button placed just fine, however it doesn't show up because the icon is white and my background is white.
Is there a way to change the color of the Route Button?
Here is the code I'm using to create the button.
self.airPlayButton = [[MPVolumeView alloc] initWithFrame:CGRectZero];
self.airPlayButton.showsVolumeSlider = NO;
[self.airPlayButton sizeToFit];
self.airPlayButton.backgroundColor = [UIColor myGreenColor];
[self addSubview:self.airPlayButton];
Basically the picture below is what I want, except I want the icon green instead of just it's background.
in reviewing Adams answer I like more clarity in that task. So I safe-guarded that code a bit:
Objective-C:
for( UIView *wnd in volumeView.subviews ) {
if( [wnd isKindOfClass:[UIButton class] ]) {
UIButton *button = (UIButton*) wnd;
UIImage *img = button.currentImage;
UIImage *img2 = [img imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[volumeView setRouteButtonImage: img2 forState:UIControlStateNormal];
break;
}
}
Swift:
for view in volumeView.subviews {
if view.isKindOfClass(UIButton) {
let buttonOnVolumeView : UIButton = view as! UIButton
volumeView.setRouteButtonImage(buttonOnVolumeView.currentImage?.imageWithRenderingMode(.AlwaysTemplate), forState: .Normal)
break;
}
}
Now it reacts on the tintColor property of volumeView and if Apple decides to add another button or change the sequence this code will still work.
To expand on lanbo's answer, you can also get the original image of the Route Button and create a copy that uses the UIImageRenderingMode.AlwaysTemplate rendering mode. That way it heeds the current tintColor.
In Swift:
let volumeView = MPVolumeView()
if let routeButton = volumeView.subviews.last as? UIButton,
let routeButtonTemplateImage = routeButton.currentImage?.imageWithRenderingMode(.AlwaysTemplate)
{
volumeView.setRouteButtonImage(routeButtonTemplateImage, forState: .Normal)
}
Create your own image and Try
setRouteButtonImage:forState:
Assigns a button image to the specified control states.
- (void)setRouteButtonImage:(UIImage *)image forState:(UIControlState)state
Parameters
image - The image to associate with the specified states.
state - The control state with which to associate the image.
Discussion
Use this to customize the appearance of the route button when it is enabled, disabled, highlighted, and so on.
Available in iOS 6.0 and later.