I have an issue where UILabel in the navigation bar is not being tinted properly when a view controller is presented modally.
The UILabel is in the navigation bar, as a child view of a UIButton, which is a child view of the UIBarButtonItem, which is the rightBarButtonItem of the navigation controller; View hierarchy:
rightBarButtonItem
-UIBarButtonItem
--UIButton <-- this is UIButtonTypeSystem, with a cart image. Tinting properly.
---UILabel <-- this is the # of items in the cart. Not tinting.
To be clear, everything works fine except the label tint during a presented modal. Before the view controller is presented, the cart is tinted blue and so is the label containing the # of cart items. When the modal is presented, the cart image dims, but the label stays blue.
I'd post images, but I do not have enough reputation, sorry.
What I have tried:
Setting the tint color on the label
Setting the label.userInteractionEnabled = NO
Setting the label.tintAdjustmentMode = UIViewTintAdjustmentModeDimmed to all available values (none of which helped)
Subclassing UIButton and drawing the # cart items during drawRect
During the view controller presentation, finding the label in the navigationItem.rightBarButtonItem.customView hierarchy and setting the tintAdjustmentMode manually.
Nothing has worked. I'm out of ideas...
Here is the code where I am creating the UIBarButtonItem:
+(UIBarButtonItem*) getCartBarButtonItemWithDelegate:(id)delegate {
NSInteger cartItems = [[DataHandler sharedInstance]cartQuantity];
NSString* num = [NSString stringWithFormat:#"%lu", (unsigned long) cartItems];
NSString* cartImageToUse = #"cart_toolbar_button_icon";
CGFloat fontSize = 11;
UILabel *label = nil;
if(cartItems > 0) {
if([num length] > 1) {
cartImageToUse = #"cartnumbered_toolbar_button2_icon";
fontSize = 10;
label = [[UILabel alloc]initWithFrame:CGRectMake(7, -3, 16, 12)];
} else {
cartImageToUse = #"cartnumbered_toolbar_button_icon";
label = [[UILabel alloc]initWithFrame:CGRectMake(7.5, -3, 16, 12)];
}
[label setFont:[UIFont systemFontOfSize:fontSize]];
[label setText: num ];
[label setTextAlignment:NSTextAlignmentCenter];
[label setBackgroundColor:[UIColor clearColor]];
}
// attempt at sub classing UIButton and drawing the number of items in the drawRect method
//CartButton *button = [CartButton buttonWithType:UIButtonTypeSystem];
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
[button setImage:[UIImage imageNamed: cartImageToUse] forState:UIControlStateNormal];
[button addTarget:delegate action:#selector(handleCartTouch:)forControlEvents:UIControlEventTouchUpInside];
[button setFrame:CGRectMake(0, 0, 25, 21)];
if(label != nil) {
[label setTextColor: button.tintColor];
[button addSubview:label];
}
UIBarButtonItem *newBackButton = [[UIBarButtonItem alloc] initWithCustomView:button];
[label release];
return newBackButton;
}
Any ideas?
The best solution I could come up with was to disable the label when the modal view controller gets presented. When the modal get dismissed, I replace the toolbar menu item (by calling getCartBarButtonItemWithDelegate) again, with a fresh, enabled label.
This way I didnt have to try and match the color that it should be. Also, this should ensure future versions of iOS will color the link appropriately, should the link (and disabled link) colors ever change.
Related
Actually i want to place image and label on the toolbar as a UIBarButtonItem and provide a clickable effect to that Button.
So what i have done here is I have created one custom view and placed Image and Label on the same custom view and finally placed this custom view as UIBarButtonItem CustomView.
But when i set target and action for the same UIBarButtonItem, it is not calling the selector method.
The entire code is below.
Can anybody suggest me what's the mistake in my code ? and is there any other approach to achieve the same ????
Early suggestions would be much appreciated.
- (void)viewDidLoad
{
[super viewDidLoad];
[self.navigationController setToolbarHidden:NO];
UIView *customView = [[UIView alloc]
initWithFrame:CGRectMake(0,0,self.navigationController.toolbar.frame.size.width,self.navigationController.toolbar.frame.size.height)];
customView.backgroundColor = [UIColor colorWithRed:62.0/255.0 green:187.0/255.0 blue:150.0/255.0 alpha:1.0];
[self.navigationController.toolbar addSubview:customView];
UIImageView *imgView = [[UIImageView alloc]initWithFrame:CGRectMake(60,0,44,44)];
imgView.image = [UIImage imageNamed:#"documentImage.png"];
[customView addSubview:imgView];
UILabel *lbl = [[UILabel alloc]initWithFrame:CGRectMake(104,0,145,44)];
lbl.text = #"Scan Document";
lbl.textAlignment = NSTextAlignmentLeft;
[customView addSubview:lbl];
UIBarButtonItem *bar = [[UIBarButtonItem alloc]initWithCustomView:customView];
bar.target = self;
bar.action = #selector(scanDocument);
self.toolbarItems = [NSArray arrayWithObjects:bar, nil];
}
If you want to create button right hand side here is the code. i have already implemented it and working fine.
//Button Right side
UIImage *imgFavRest = [UIImage imageNamed:#"documentImage.png"];
UIButton *cart = [UIButton buttonWithType:UIButtonTypeCustom];
[cart setImage:imgFavRest forState:UIControlStateNormal];
cart.frame = CGRectMake(0, 0, imgFavRest.size.width, imgFavRest.size.height);
[cart addTarget:self action:#selector(showCart) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *rightBtn = [[UIBarButtonItem alloc] initWithCustomView:cart];
self.navigationItem.rightBarButtonItem = rightBtn;
Then use method like this . that's all
-(void)cartItemCount{
// Method
}
float textwidth = 50; // according to your text
UIImage *image = [UIImage imageNamed:#"logout"];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.bounds = CGRectMake( 10, 0, image.size.width+textwidth, image.size.height );
[btn addTarget:self action:#selector(scanDocument) forControlEvents:UIControlEventTouchUpInside];
[btn setImage:image forState:UIControlStateNormal];
[btn setTitle:#"test" forState:UIControlStateNormal];
[btn setTitleEdgeInsets:UIEdgeInsetsMake(0.0, 5.0, 0.0, 0.0)];
//Adjust the coordinates and size of your button as your requirement.This is a sample code to guide you.
//PS:Take a UIButton in the nib file>Make it a custom button>Connect the IBOutlet to your custom button in the nib file.Thats it.
UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithCustomView:btn];
self.navigationItem.rightBarButtonItem = rightButton;
I see very complicated answers, all of them using code. However, if you are using Interface Builder, there is a very easy way to do this:
Select the button and set a title and an image. Note that if you set
the background instead of the image then the image will be resized if
it is smaller than the button.IB basic image and title
Set the position of both items by changing the edge and insets. You
could even control the alignment of both in the Control section.
IB position set IB Control set
You could even use the same approach by code, without creating UILabels and UIImages inside as other solutions proposed. Always Keep It Simple!
EDIT: Attached a small example having the 3 things set (title, image and background) with correct insets Button preview
Note:: UIBarButtonItem inherits from UIBarItem and NSObject so it doesn't know anything about touches. It would be nice if the docs mentioned that the action and target properties only apply if the custom view is a UIButton.
I have a navigation controller with a custom back button on the left. I do this programmatically so this is not an auto-layout issue. My problem is that the navigation controller title is not centered, it is going off the right side of the screen. I remember seeing a fix for this awhile back dealing with setting some type of fixed space as the right bar button item, but I cannot seem to find anything similar to this now.
Could someone tell me how to set the navigation controller title to centered and if the title is too big for its space, set nav bar title to fix its font size to fit the width of title space. This all needs to be done programmatically, thanks!
In navigation controller, by default, the view controller A that pushes current view controller B. The title of A will show up in backBarButton in view controller B.
The navigation controller title not centered is also because the previous view controller title is too long.
To counter that, use this in viewWillAppear of view controller A:
self.navigationItem.backBarButtonItem= UIBarButtonItem(title: "",
style: UIBarButtonItemStyle.Plain, target: nil, action: nil)
self.navigationItem.backBarButtonItem!.title = ""`
Thanks so much for the answers, they were useful in helping my find a solution. My solution was to use the titleView property of the navigation controller. It sets the title without having to go through the trouble of making a custom UIView and the setAdjustsFontSizeToFitWidth property solved my problem of the font size being too big. I've added a little extra formatting to make it look nice, but I won't post it since it doesn't have to do with my question. Here is the code I am using:
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, self.view.frame.size.width-60, self.navigationController.navigationBar.frame.size.height)];
titleLabel.text = #"This is my big, long title";
titleLabel.textColor = [UIColor blackColor];
titleLabel.textAlignment = UITextAlignmentCenter;
[titleLabel setAdjustsFontSizeToFitWidth:YES];
self.navigationItem.titleView = titleLabel;
You have to add custom view in the navigation
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(10, 0, 150, 44)];
UILabel *titleLabel=[[UILabel alloc] initWithFrame:CGRectMake(10, 165,370, 25)];
titleLabel.text=#"Home";
titleLabel.textColor=[UIColor whiteColor];
[view addSubview:titleLabel];
[self.navigationController.navigationBar addSubview:view];
Try out this, it would help you and it is tested.
Objective C version
UIButton * button = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 50, 50)];
[button addTarget:self action:#selector(yourSelector:) forControlEvents:UIControlEventTouchUpInside];
[button setTitle:#"<" forState:UIControlStateNormal];
button.titleEdgeInsets = UIEdgeInsetsMake(-3, -15, 3, 15);
[button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
UIBarButtonItem *leftItem = [[UIBarButtonItem alloc]initWithCustomView:button];
self.navigationItem.leftBarButtonItem = leftItem;
Swift version
button = UIButton(frame: CGRectMake(0, 0,50, 50))
button?.addTarget(self, action: "backButtonTapped:", forControlEvents: UIControlEvents.TouchUpInside)
button?.setTitle("<", forState: .Normal)
button?.titleLabel?.font = UIFont(name: kFontHelveticaNeueRegular, size: 30)
button?.titleEdgeInsets = UIEdgeInsetsMake(-3, -15, 3, 15)
button?.setTitleColor(UIColor.whiteColor(), forState: .Normal)
var leftItem = UIBarButtonItem(customView: button!)
controller.navigationItem.leftBarButtonItem = leftItem
Add following method in your Utilities class
+ (void)setTitle:(NSString *)title forViewController:(UIViewController *)viewController {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
[label setTextAlignment:NSTextAlignmentCenter];
[label setTextColor:[UIColor whiteColor]];
[label setFont:[UIFont boldSystemFontOfSize:18]];
[label setText:title];
[label sizeToFit];
viewController.navigationItem.titleView = label;
}
Use across view controllers as follows
[Utilities setTitle:#"Title for View Controller" forViewController:self];
Add both leftbarbutton and Rightbarbutton . Usually back button exist . If you add an empty right bar button , title will get centered.
What is the proper way to change height of navigation bar?
I need to create custom title in navigation bar, it should contains two UILabels one above other. The Title should be resized to fit those UILabels.
Should I override sizeThatFits: method in my custom TitleView, would other buttons correctly change to fit that size? How can I change a size of NavigationBar?
That is what I need to create using latest SDK features.
Create the following class category (you can create it in your implementation file):
#import "objc/runtime.h"
#interface UINavigationBar (CustomHeight)
- (void)setHeight:(CGFloat)height;
#end
static char const *const kHeight = "Height";
#implementation UINavigationBar (CustomHeight)
- (void)setHeight:(CGFloat)height
{
objc_setAssociatedObject(self, kHeight, #(height), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSNumber *)height
{
return objc_getAssociatedObject(self, kHeight);
}
- (CGSize)sizeThatFits:(CGSize)size
{
CGSize newSize;
if (self.height) {
newSize = CGSizeMake(self.superview.bounds.size.width, [self.height floatValue]);
} else {
newSize = [super sizeThatFits:size];
}
return newSize;
}
#end
And after that, simply call [self.navigationController.navigationBar setHeight:100.0] in your viewDidLoad or where you need it. Works in both iOS 7.1 and 8.1.
Disclaimer: Any alteration of the API and its functions is prone to future issues with new OS releases! Apple does not intend to allow us to change the navigation bar height (except for some rare instances) so use any solution wisely after assessing the risks vs advantages.
Looking at that design that you posted, I don't have the impression that the bar is really higher than the standard 44pt. Please note that starting with iOS7 the status bar is integrated into the same bar and the 20pt of the status bar is added to the total height.
IMHO, the only problem you need to solve is to stack the title/subtitle, and that can be easily done with a custom titleView, as Kampai has demonstrated.
Add custom view for both navigation title and navigation right bar button.
Here how you can add title view like above.
// Custom view for navigation title.
UIView *customTitleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 44)];
UILabel *label1 = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 22)];
label1.text = #"Stasik";
label1.font = [UIFont fontWithName:#"HelveticaNeue-Light" size:20];
label1.textAlignment = NSTextAlignmentCenter;
[customTitleView addSubview:label1];
UILabel *label2 = [[UILabel alloc] initWithFrame:CGRectMake(0, 22, 100, 22)];
label2.text = #"Stasik iPhone";
label2.font = [UIFont fontWithName:#"HelveticaNeue-Light" size:16];
label2.textAlignment = NSTextAlignmentCenter;
label2.textColor = [UIColor darkGrayColor];
[customTitleView addSubview:label2];
self.navigationItem.titleView = customTitleView;
// Custom view for right navigation.
UIButton *upButton = [UIButton buttonWithType:UIButtonTypeCustom];
upButton.frame = CGRectMake(0, 0, 20, 44);
[upButton setImage:[UIImage imageNamed:#"up"] forState:UIControlStateNormal];
[upButton addTarget:self action:#selector(upButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *upButtonBarItem = [[UIBarButtonItem alloc] initWithCustomView:upButton];
UIButton *downButton = [UIButton buttonWithType:UIButtonTypeCustom];
downButton.frame = CGRectMake(0, 0, 20, 44);
[downButton setImage:[UIImage imageNamed:#"down"] forState:UIControlStateNormal];
[downButton addTarget:self action:#selector(downButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *downButtonBarItem = [[UIBarButtonItem alloc] initWithCustomView:downButton];
// Remove trailing space for right view.
UIBarButtonItem *nagativeSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
nagativeSpace.width = -11;
self.navigationItem.rightBarButtonItems = #[nagativeSpace, upButtonBarItem, downButtonBarItem];
// Left item
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
backButton.frame = CGRectMake(0, 0, 40, 44);
[backButton setImage:[UIImage imageNamed:#"back"] forState:UIControlStateNormal];
[backButton addTarget:self action:#selector(backButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
// Remove leading space for left view.
nagativeSpace.width = -15;
UIBarButtonItem *backButtonBarItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
self.navigationItem.leftBarButtonItems = #[nagativeSpace, backButtonBarItem];
OutPut:
Arrow images are different than OP's requirement but it serves layout for navigation views.
From above code make change in nagativeSpace.width value to arrange buttons with accurate distance from left as well as right margins.
I really need your help with this one (first post on SO -- be gentle):
I have two dynamic UIButtons which I would like to have centered in a UIView, which in turn should be centered in a UINavigationbar and UIToolbar. I can't - despite a lot of Googling - seem to figure out a proper way to do this.
This is what I've done so far:
In viewDidLoad, I add the two buttons as subviews and set the view as the UINavigationbar's titleView
self.myClass.viewForTitleAndButton = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 120, 32)];
[self.myClass.viewForTitleAndButton setBackgroundColor:[UIColor blackColor]];
[self.myClass.viewForTitleAndButton addSubview:self.myClass.myButton];
[self.myClass.viewForTitleAndButton addSubview:self.myClass.myOtherButton];
self.navigationItem.titleView = self.myClass.viewForTitleAndButton;
In a method being triggered when I press certain buttons, I set the title (and bounds) of one of the buttons depending on what's clicked:
CGSize titleSize = [title sizeWithAttributes:#{NSFontAttributeName : [UIFont italicSystemFontOfSize:17.0]}];
CGSize screenSize = [UIScreen mainScreen].bounds.size;
CGFloat newX = (screenSize.width - titleSize.width) / 2;
CGRect buttonFrame = self.myClass.myButton.frame;
//Removing the line below doesn't do any difference at the moment
self.myClass.myButton.bounds = CGRectMake(newX, buttonFrame.origin.y, titleSize.width+8, buttonFrame.size.height);
[self.myClass.myButton setTitle:title forState:UIControlStateNormal];
NSLog(#"Title: %#", title);
//title is a NSString that changes depending on what is clicked. I am 100% sure it changes as I can see it in the log every time the method is triggered.
The problem is that the title of myButton is not changed. It worked before with the very same button when it was placed in a different spot and not as a subview.
Q1: What am I missing to make the title of the button change?
Q2: Is adding the buttons as subViews to a view that is then placed in the navigationbar and toolbar respectively a sound way to accomplish what I want?
This is really bugging me, any pointers in the right direction is much appreciated.
I don't think you can add a button which is already an outlet of a view controller. Thinking in another way, a button(view) can only has one superview.
Create button dynamically for the title view.
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *iv = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 160, 44)];
iv.backgroundColor = [UIColor greenColor];
titleButton = [UIButton buttonWithType:UIButtonTypeCustom];
titleButton.frame = CGRectMake(0, 0, 120, 44);
[titleButton setTitle:#"test" forState:UIControlStateNormal];
[titleButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[iv addSubview:titleButton];
self.navigationItem.titleView = iv;
}
//some event to change the button title
- (void)click:(UIButton *)button
{
[titleButton setTitle:#"I changed" forState:UIControlStateNormal];
}
I'm trying to make a custom back button to pop back to parent in nav controller. I understand I should've made the back button in parent controller itself
self.navigationItem.backBarButtonItem= backBarButton
The button was just default button with custom text, but it worked. None of formatting or fonts showed up.
So instead I made a custom leftBarButton in child VC:
UIButton *backBtn= [[UIButton alloc] init];
backBtn.backgroundColor = [UIColor clearColor];
backBtn.titleLabel.font = [UIFont fontWithName:#"CrimeFighter BB" size:20];
backBtn.titleLabel.textColor = [UIColor whiteColor];
backBtn.titleLabel.text = #"back";
[backBtn addTarget:self action:#selector(pop) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *backBarButton = [[UIBarButtonItem alloc] initWithCustomView:backBtn];
self.navigationItem.leftBarButtonItem = backBarButton;
Its working fine, but the button is not visible at all!
New attempt:
Doing an alloc & init on a UIButton isn't the right way to create a button in code.
The way to programatically create a button is:
UIButton * backBtn = [UIButton buttonWithType: UIButtonTypeRoundedRect];
Original attempt:
You need to give your custom back button a proper size. Try doing this before creating the "UIBarButtonItem".
backBtn.frame = CGRectMake(20.0f, 0.0f, 70.0f, 30.0f);
The last number is the height and the second to last number is the button width.