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.
Related
I want to create a header toolbar like shown in the image below. It is from the web view of the Twitter app.
I created a UIToolbar and put it at the top. Then I inserted the Buttons left and right and changed the Identifier to get the correct symbols.
My problem is the text in the middle. I create a UIBarButtonItem and placed it between the buttons. Here is my Problem.
How to I achieve that the UIBarButtonItem title does not overlap the left and the right button when the title is to long?
In my case:
How do I achieve that the title gets ... at the end if it gets to long?
How can I set the sub title?
How can I achieve that the button is not clickable, i.e., has color black?
Edit Using the answer from #Viral Savaj: Here is what it looks like:
To test if the title is too long, you should use character counting. Let myHeaderBarString represent your string for the title. You will probably have to adjust this number to find the right length before it gets truncated.
if count(myHeaderBarString) > 40 {
myHeaderBarString = myHeaderBarString.substringToIndex(40)
myHeaderBarString.append("...")
}
For a subtitle, you should insert a new view with a UILabel inside it.
You can set custom title view to the navigation bar like this way.
//To hide default back button
self.navigationItem.hidesBackButton=YES;
//Title View for Navigation
UIView *navTitle1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 44)];
[navTitle1 setBackgroundColor:[UIColor lightGrayColor]];
//Left View button and separator
UIButton *crossBarButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 44, 44)];
[crossBarButton setTitle:#"X" forState:UIControlStateNormal];
//Center view with two buttons and seprator for them
UILabel *topTitle = [[UILabel alloc] initWithFrame: CGRectMake(50,0, self.view.bounds.size.width-100, 22)];
topTitle.text = #"text";
topTitle.font = [UIFont systemFontOfSize:25];
topTitle.lineBreakMode = NSLineBreakByCharWrapping;
UILabel *subTitle = [[UILabel alloc] initWithFrame: CGRectMake(50,20, self.view.bounds.size.width-100, 18)];
subTitle.text = #"subtext";
subTitle.font = [UIFont systemFontOfSize:18];
subTitle.lineBreakMode = NSLineBreakByCharWrapping;
//Right button with seprator before that
UIButton *uploadBarButton = [[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width-50, 0, 44, 44)];
[uploadBarButton setTitle:#"U" forState:UIControlStateNormal];
[navTitle1 addSubview:crossBarButton];
[navTitle1 addSubview:topTitle];
[navTitle1 addSubview:subTitle];
[navTitle1 addSubview:uploadBarButton];
self.navigationItem.titleView = navTitle1;
You can refer THIS for more detail.
Use BarButtonItem.customView, it works.
let button = UIButton(frame: CGRectMake(0,0,200,40))
button.titleLabel?.adjustsFontSizeToFitWidth = true
button.setTitle("gogogogogogogogoogogogogogogogogogoogo", forState: .Normal)
button.setTitleColor(UIColor.blackColor(), forState: .Normal)
button.addTarget(self, action: "showMessage:", forControlEvents: .TouchUpInside)
let rightBarButtonItem = UIBarButtonItem()
rightBarButtonItem.customView = button
self.navigationItem.rightBarButtonItem = rightBarButtonItem
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.
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.