ios back button in the bar - ios

it's possible insert a toolbutton in a tool bar with the shape like the back button used in the navigation bar?
here is what I mean:
thanks in advance!

You can't do it, at least not with the shape of a back button, the one with the arrow end on the left. backBarButtonItem is only a property of UINavigationItem.
You can either use a rectangular button on your toolbar to go back (although I don't think Apple is fond of that... you should read the iOS Human Interface Guidelines),
OR you can add a custom back button somewhere else on the screen. For instance, if your toolbar is at the bottom you can add a custom back button to the top-left corner of the screen to keep things tidy. This way, you would be saving the screen space of having a navigation bar just for the back button.

typeonerror has code on github that contains what you need; it's actually for customising the back button on the a view controller, but you can use it to create a back button on a toolbar instead:
https://github.com/typeoneerror/BBCustomBackButtonViewController
In particular, code like the following (which actually came from stackoverflow, Customization of UINavigationBar and the back button ):
+ (UIBarButtonItem *)styledBackBarButtonItemWithTarget:(id)target selector:(SEL)selector;
{
UIImage *image = [UIImage imageNamed:#"button_back"];
image = [image stretchableImageWithLeftCapWidth:20.0f topCapHeight:20.0f];
NSString *title = NSLocalizedString(#"Back", nil);
UIFont *font = [UIFont boldSystemFontOfSize:12.0f];
UIButton *button = [UIButton styledButtonWithBackgroundImage:image font:font title:title target:target selector:selector];
button.titleLabel.textColor = [UIColor blackColor];
CGSize textSize = [title sizeWithFont:font];
CGFloat margin = (button.frame.size.height - textSize.height) / 2;
CGFloat marginRight = 7.0f;
CGFloat marginLeft = button.frame.size.width - textSize.width - marginRight;
[button setTitleEdgeInsets:UIEdgeInsetsMake(margin, marginLeft, margin, marginRight)];
[button setTitleColor:[UIColor colorWithRed:53.0f/255.0f green:77.0f/255.0f blue:99.0f/255.0f alpha:1.0f] forState:UIControlStateNormal];
return [[[UIBarButtonItem alloc] initWithCustomView:button] autorelease];
}

Related

UIBarButtonItem Target Method is not working

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.

UILabel as subview of UIBarButtonItem.customView not dimming when presenting view controller

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.

View with subviews in a uinavigationbar and uitoolbar

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];
}

UIBarButtonItem tap area

I create left Bar button item with next method:
- (void)leftButtonOnNavigationItem:(NSString *)imageName type:(NSInteger)type
{
UIImage *backImg = [UIImage imageNamed:imageName];
UIButton *backBtn = [[UIButton alloc] initWithFrame:CGRectMake(0.f, 0.f, backImg.size.width, backImg.size.height)];
if (type == 0)
[backBtn addTarget:self.navigationController action:#selector(pop) forControlEvents:UIControlEventTouchUpInside];
else
[backBtn addTarget:self action:#selector(leftMake) forControlEvents:UIControlEventTouchUpInside];
backBtn.contentMode = UIViewContentModeCenter;
[backBtn setImage:backImg forState:UIControlStateNormal];
UIView *backBtnView = [[UIView alloc] initWithFrame:backBtn.bounds];
backBtnView.bounds = CGRectOffset(backBtnView.bounds, -6, 0);
[backBtnView addSubview:backBtn];
UIBarButtonItem *backBarBtn = [[UIBarButtonItem alloc] initWithCustomView:backBtnView];
self.navigationItem.leftBarButtonItem = backBarBtn;
}
I need add button on View because when I use CGRectOffset for button it is not work. So with this case my button on one od the UIViewController shown
So it is what I want. But UIBarButton began clicked only on UIBarButton (area of the rectangle). But when I add only button in UIBarButtonItem it is work even if I clicked on area of UINavigationBar that you can see on screen.
I add button like this:
- (void)leftButtonOnNavigationItem:(NSString *)imageName type:(NSInteger)type
{
UIImage *backImg = [UIImage imageNamed:imageName];
UIButton *backBtn = [[UIButton alloc] initWithFrame:CGRectMake(0.f, 0.f, backImg.size.width, backImg.size.height)];
if (type == 0)
[backBtn addTarget:self.navigationController action:#selector(pop) forControlEvents:UIControlEventTouchUpInside];
else
[backBtn addTarget:self action:#selector(leftMake) forControlEvents:UIControlEventTouchUpInside];
backBtn.contentMode = UIViewContentModeCenter;
[backBtn setImage:backImg forState:UIControlStateNormal];
// UIView *backBtnView = [[UIView alloc] initWithFrame:backBtn.bounds];
// backBtnView.bounds = CGRectOffset(backBtnView.bounds, -6, 0);
// [backBtnView addSubview:backBtn];
UIBarButtonItem *backBarBtn = [[UIBarButtonItem alloc] initWithCustomView:backBtn];//View];
self.navigationItem.leftBarButtonItem = backBarBtn;
}
and now my button shown like this
So CGRectOffset not work and my UIBarButton very close to left side of screen, but it is work fine by tap all area on navigation bar, that you see on screen. So I can touch in all area on navigation Bar and UIBarButton will work fine
So I need: UIBarButton must shown like in first case with more area from left side. But it must work by click not only button but all surround ares like in second case. What I must do?
EDIT
In first case button clicked if i tap next area
In second case button clicked if i tap next area
I need position of button like in first case (more origin.x from left side) but clickable area like in second case
All controls/elements that can be interacted with inherit from UIView. UIView provides a method called - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;
It is possible to reimplement this method in your own subclass to increase or decrease the valid hit region of the view (or button in your case). For example, to grow the hit region by 5 points in all directions
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
return CGRectContainsPoint( CGRectInset( self.bounds, -5, -5 ), point );
}
Note the negative values when using CGRectInset(). This is because the function is designed for shrinking a CGRect, so by specifying a negative value, the function will expand the CGRect.
Hope this helps!
You can use UIEdgeInsetsMake. It work for me.
UIImage *buttnImage=[UIImage imageNamed:imageName];
UIButton *backButton=[UIButton buttonWithType:UIButtonTypeCustom];
[backButton setImage:buttnImage forState:UIControlStateNormal];
backButton.frame=CGRectMake(0, 0, (buttnImage.size.width+leftMargin+rightMargin), (buttnImage.size.height+topMargin+bottomMargin));
[backButton setImageEdgeInsets:UIEdgeInsetsMake(topMargin, leftMargin, bottomMargin, rightMargin)];
UIBarButtonItem *backBtn=[[UIBarButtonItem alloc]initWithCustomView:backButton];
self.navigationItem.leftBarButtonItems=#[backBtn];
A view's frame is the size and position of the view within a superview (its parent). So when you go to set backBtnView initWithFrame try:
UIView *backBtnView = [[UIView alloc]
initWithFrame:CGRectOffset(backBtn.frame, -6.0, 0.0)];
and forget about bounds all together, I think that will put you in the right direction.
I fixed it in used accessibility frame.
Just set accessibility frame for button with increased height and width and it will work.

How can I create a big, red UIButton with iOS?

Using iOS, how would I go about creating a red "delete" button similar to the one used when deleting contacts on the iPhone?
You first start with a stretchable image:
alt text http://grab.by/4lP
Then you make a button with the stretched image as the background and apply text.
UIButton *sampleButton = [UIButton buttonWithType:UIButtonTypeCustom];
[sampleButton setFrame:CGRectMake(kLeftMargin, 10, self.view.bounds.size.width - kLeftMargin - kRightMargin, 52)];
[sampleButton setTitle:#"Button Title" forState:UIControlStateNormal];
[sampleButton setFont:[UIFont boldSystemFontOfSize:20]];
[sampleButton setBackgroundImage:[[UIImage imageNamed:#"redButton.png"] stretchableImageWithLeftCapWidth:10.0 topCapHeight:0.0] forState:UIControlStateNormal];
[sampleButton addTarget:self action:#selector(buttonPressed) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:sampleButton];
Obviously, you will need to adjust the frame origin and size to match your app, as well as the target, selector, and title.
I've also made some buttons...retina and non-retina versions
If you want to use them in a Cell just use the following code in cellForRowAtIndexPath:
UIButton *sampleButton = [UIButton buttonWithType:UIButtonTypeCustom];
[sampleButton setFrame:[cell.contentView frame]];
[sampleButton setFrame:CGRectMake(0, 0, cell.bounds.size.width-20, 44)];
[sampleButton setBackgroundImage:[UIImage imageNamed:#"button_red.png"] forState:UIControlStateNormal];
[cell addSubview:sampleButton];
I think those ones are better (and they look fine on retina display too) :
.png generated from this very nice .psd file : http://www.teehanlax.com/blog/2010/08/12/iphone-4-gui-psd-retina-display/
And then use it as a strechable image for the background of your UIButton:
UIImage* greenButton = [UIImage imageNamed:#"UIButton_green.png"];
UIImage *newImage = [greenButton stretchableImageWithLeftCapWidth:greenButton.size.width/2 topCapHeight:greenButton.size.height/2];
[callButton setBackgroundImage:newImage forState:UIControlStateNormal];
Probably the simplest way to do it is to snag this iPhone GUI Photoshop file that contains lots of UI elements in PSD layers, then change the tint of the large button in Photoshop and save it as a PNG.
One advantage of doing it this way is that you can also create versions for button selected and/or highlight state and assign the images to a standard UIButton.
You can create a separate section in your grouped table view, give that section only one row, and set that cell's background image to a red gradient image. You'll have to recreate that image on your own, though.
I would like to contribute a solution which does not use images but which gives the same look as the 'delete' button in Contacts.
In the below example I will use assume a UITableView with grouped, static cells, designed in storyboard. Make one of the sections have only a single cell. That cell will be the 'delete' button. Give the cell a red background color (f.e. Red 221, Green 0, Blue 2)
What we will do is add two GradientLayers to the cell. The first will cover the upper half of the cell. The second will cover the lower half.
Add QuartzCore to your implementation file:
#import <QuartzCore/QuartzCore.h>
Start with making an outlet to this cell:
#property (strong, nonatomic) IBOutlet UITableViewCell *cellDelete;
Create a method in which the cell will be formatted:
- (void)formatCellDelete
{
// Top Gradient //
CAGradientLayer *gradientTop = [CAGradientLayer layer];
// Make a frame for the layer based on the size of the cells contentView
// Make it half the height
// The width will be -20 so the gradient will not overflow
CGRect frame = CGRectMake(0, 0, _cellDelete.contentView.frame.size.width - 20, _cellDelete.contentView.frame.size.height / 2);
gradientTop.frame = frame;
gradientTop.cornerRadius = 8;
UIColor* topColor = [UIColor colorWithWhite:1.0f alpha:0.75f];
UIColor* bottomColor = [UIColor colorWithWhite:1.0f alpha:0.0f];
gradientTop.colors = [NSArray arrayWithObjects:(id)[topColor CGColor], (id)[bottomColor CGColor], nil];
[_cellDelete.contentView.layer setMasksToBounds:YES];
[_cellDelete.contentView.layer insertSublayer:gradientTop atIndex:0];
// Bottom Gradient //
CAGradientLayer *gradientBottom = [CAGradientLayer layer];
// Make a frame for the layer based on the size of the cells contentView
// Make it half the height
// The width will be -20 so the gradient will not overflow
frame = CGRectMake(0, 0, _cellDelete.contentView.frame.size.width - 20, _cellDelete.contentView.frame.size.height / 2);
// And move to bottom
frame.origin.y = frame.size.height;
gradientBottom.frame = frame;
topColor = [UIColor colorWithWhite:0.0f alpha:0.05f]; //0.20
bottomColor = [UIColor colorWithWhite:0.0f alpha:0.0f];
gradientBottom.colors = [NSArray arrayWithObjects:(id)[topColor CGColor], (id)[bottomColor CGColor], nil];
[_cellDelete.contentView.layer setMasksToBounds:YES];
[_cellDelete.contentView.layer insertSublayer:gradientBottom atIndex:0];
// Define a selected-backgroundColor so the cell changes color when the user tabs it
UIView *bgColorView = [[UIView alloc] init];
[bgColorView setBackgroundColor:[UIColor colorWithRed:(float)(0.502) green:0.0 blue:0.0 alpha:1.000]];
bgColorView.layer.cornerRadius = 10;
[_cellDelete setSelectedBackgroundView:bgColorView];
}
The above will give your cell the glass-look like the 'delete' button in Contacts.
But we also want it to change color when the user taps it. This is what the last piece of code in the above method will do. It will set a different view with a darker color as the selectedBackgroundView.
After tapping the cell will stay selected and will keep its dark color. To automatically deselect the cell we do the following:
Start with a constant which defines the section nr of your delete cell:
static NSInteger const SECTION_DELETE = 1;
Now implement the (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath method (defined in UITableViewDelegate):
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.section == SECTION_DELETE){
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
// Navigation logic may go here. Create and push another view controller.
/*
 *detailViewController = [[ alloc] initWithNibName:#"" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
*/
}

Resources