I have an UIToolbarwith 5 items:
UIBarButtonItem with image
UIBarButtonItem flex width
UIBarButtonItem with custom view (UISearchBar)
UIBarButtonItem flex width
UIBarButtonItem with image
When I select the UISearchBar, I get it to keep its correct size and become active. However, I would like the image to the left and to the right to disappear and give the UISearchBar the full width of the UIToolbar. How do I do that?
This is what I have:
https://dl.dropbox.com/u/3077127/demo_1.mov
And this is what I want:
https://dl.dropbox.com/u/3077127/demo_2.mov
This is my code:
#pragma mark View lifecycle
- (void)viewDidLoad {
[...]
SearchBar *mySearchBar = [[SearchBar alloc] init];
mySearchBar.delegate = self;
[mySearchBar sizeToFit];
[mySearchBar setAutocapitalizationType:UITextAutocapitalizationTypeNone];
[mySearchBar setTintColor:[UIHelpers getSlColor]];
CGRect searchBarFrame = mySearchBar.frame;
searchBarFrame.size.width = 218;
[mySearchBar setFrame:searchBarFrame];
UIView *searchBarContainer = [[UIView alloc] initWithFrame:mySearchBar.frame];
[searchBarContainer addSubview:mySearchBar];
[searchBarContainer setTag:99];
UIBarButtonItem *left = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"location-arrow"] style:UIBarButtonItemStyleBordered target:self action:nil];
UIBarButtonItem *right = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"location-arrow"] style:UIBarButtonItemStyleBordered target:self action:nil];
UIBarButtonItem *flex = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
UIBarButtonItem *search = [[UIBarButtonItem alloc] initWithCustomView:searchBarContainer];
NSArray *items = [[NSArray alloc] initWithObjects:left, flex, search, flex, right, nil];
UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
[toolbar setItems:items];
[toolbar setTintColor:[UIHelpers getSlColor]];
self.tableView.tableHeaderView = toolbar;
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectNull];
[...]
[super viewDidLoad];
}
#pragma mark -
Here is my answer to a similar question posted here
The key to a correct animation is to specify UIViewAnimationOptionLayoutSubviews as an option for the animation.
Not sure if you have tried this, but maybe you can use the UISearchBarDelegate methods to get notified when the user clicks on the search bar.
Example:
#pragma mark - UISearchBarDelegate Methods
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
// Remove the right and left buttons from the ToolBar
[self updateToolBarWithImages:NO];
}
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar {
// Add back the right and left buttons to the ToolBar
[self updateToolBarWithImages:YES];
}
#pragma mark - Private Methods
// Custom method used to Update the ToolBar
- (void)updateToolBarWithImages:(BOOL)iShowImages {
// Logic to update ToolBar based on the BOOL value in showImages
// use "setItems:animated:" method of UIToolBar to set the ToolBar Items
[toolBar setItem:items animated:YES];
}
You shouldn't use a ToolBar for that.
Simply use a NavigationBar, with your 2 right and left ButtonItems, plus add to the NavigationBar's titleView a SearchBar with the appropriate delegates.
So you don't have to resize your NavigationBar. It's just about adding/removing the NavigationBar's right and left ButtonItems animated like so:
if (self.searchBar.isActive) {
[self.navigationItem setLeftBarButtonItem:nil animated:YES];
[self.navigationItem setRightBarButtonItem:nil animated:YES];
}
else {
[self.navigationItem setLeftBarButtonItem:self.leftButton animated:YES];
[self.navigationItem setRightBarButtonItem:self.rightButton animated:YES];
}
Hope this helps!
Related
I am implementing a view with a date picker and a toolbar.
I have the following code:
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(frame), 44)];
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self
action:#selector(didSelectCancelButton)];
UIBarButtonItem *flexible = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:#selector(didSelectDoneButton)];
NSArray *buttons = #[cancelButton, flexible, doneButton];
[self.toolbar setItems:buttons
animated:NO];
self.datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 50, CGRectGetWidth(frame), 216)];
[self addSubview:self.datePicker];
[self addSubview:self.toolbar];
}
return self;
}
- (IBAction)didSelectCancelButton {
if ([self.delegate respondsToSelector:#selector(datePickerDidCancelDateSelection:)]) {
[self.delegate datePickerDidCancelDateSelection:self];
}
}
- (IBAction)didSelectDoneButton {
NSLog(#"");
}
But when I click the buttons, no action is performed. The methods are not invoked.
Can you tell what am I doing wrong?
Thanks
EDIT:
Turned out there was a gesture recognizer that was capturing the touch events.
Fixing that resolved this problem.
I suspect your date picker (which is as wide as the toolbar is) is somehow inhibiting your buttons from getting user touches.
Try reversing these two lines to this:
[self addSubview:self.datePicker];
[self addSubview:self.toolbar];
Do you have any UIGestureRecognizer objects, if you do try to disable them and test.
I already read this question QLPreviewController remove or add UIBarButtonItems but it's not what I'm looking for. I would like to keep the "Print" button in the navigation Bar but also add a new "Delete Document" button in the navigation bar.
I tried this:
QLPreviewController *previewer = [[[QLPreviewController alloc] init] autorelease];
[previewer setDataSource:self];
UIBarButtonItem *saveButton = [[UIBarButtonItem alloc]initWithTitle:#"Salva Documento" style:UIBarButtonItemStyleBordered target:self action:#selector(saveFileToDocuments)];
NSArray *buttons = [NSArray arrayWithObjects:[[previewer navigationItem]rightBarButtonItem],saveButton, nil];
[[previewer navigationItem]setRightBarButtonItems:buttons];
But it didn't work.
Because you said "4.x will be fine", there's your problem.
The documentation for UINavigationItem [setRightBarButtonItems: animated:] (documentatin linked there for you) say that this function only works on iOS 5.0 and newer.
It will not work on iOS 4.0.
Also, you should add an animated: parameter to that setRightBarButtonItems: call.
UIBarButtonItem *rbb;
-(void)addRightButton{
if (!rbb) {
UIButton *orderButton = [UIButton buttonWithType:UIButtonTypeCustom];
orderButton.frame = CGRectZero;
rbb = [[UIBarButtonItem alloc] initWithCustomView:orderButton];
}
self.navigationItem.rightBarButtonItem = rbb;
}
- (void)viewDidLoad{
[super viewDidLoad];
[self performSelector:#selector(addRightButton) withObject:nil afterDelay:0.2];
}
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[self addRightButton];
}
I have a very tricky problem and after long searching (google, stackoverflow, ...) i didn't get the solution that works for me.
Let me introduce you in my current choosen architecture:
I have a a AppDelegate, which has a UIView that contains a UINavigationController and the application didFinishLaunchingWithOptions: contains:
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 400)];
UIViewController *myController = [[UIViewController alloc] init];
myController.view = myView;
FSCScrumRootView * myRootView = [[FSCScrumRootView alloc] initWithNibName:#"FSCScrumRootView" bundle:[NSBundle mainBundle]];
[myController.view addSubview:myRootView.navigation.view];
[self.window addSubview:myController.view];
[self.window makeKeyAndVisible];
return YES;
}
In my FSCScrumRootView (inherits from UIViewController) i init the view like this:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
self.navigation = [[[UINavigationController alloc] init] autorelease];
self.scrumProjectsList = [[[FSCScrumProjectListView alloc] init] initWithNibName:#"FSCScrumProjectListView" bundle:nil];
[navigation pushViewController:scrumProjectsList animated:YES];
[navigation view];
}
return self;
}
In my FSCScrumProjectListView (it is inherited from UITableViewController) i have implemented the viewDidLoad as following:
- (void)viewDidLoad
{
[super viewDidLoad];
//Set the title
self.navigationItem.title = #"Scrum Projects";
UIBarButtonItem *myRefreshButton = [[[UIBarButtonItem alloc] initWithTitle:#"Refresh" style:UIBarButtonSystemItemRefresh target:self action:#selector(refreshList)] autorelease];
self.navigationItem.leftBarButtonItem = myRefreshButton;
UIBarButtonItem *myLogoutButton = [[UIBarButtonItem alloc] initWithTitle:#"Logout" style:UIBarButtonSystemItemCancel target:self action:#selector(logout)];
self.navigationItem.rightBarButtonItem = myLogoutButton;
//Initialize the toolbar
toolbar = [[UIToolbar alloc] init];
toolbar.barStyle = UIBarStyleDefault;
//Set the toolbar to fit the width of the app.
[toolbar sizeToFit];
//Caclulate the height of the toolbar
CGFloat toolbarHeight = [toolbar frame].size.height;
//Get the bounds of the parent view
CGRect rootViewBounds = self.parentViewController.view.bounds;
//Get the height of the parent view.
CGFloat rootViewHeight = CGRectGetHeight(rootViewBounds);
//Get the width of the parent view,
CGFloat rootViewWidth = CGRectGetWidth(rootViewBounds);
//Create a rectangle for the toolbar
CGRect rectArea = CGRectMake(0, rootViewHeight - toolbarHeight, rootViewWidth, toolbarHeight);
//Reposition and resize the receiver
[toolbar setFrame:rectArea];
//Create a button
UIBarButtonItem *infoButton = [[UIBarButtonItem alloc]
initWithTitle:#"Info" style:UIBarButtonItemStyleBordered target:self action:#selector(info_clicked:)];
[toolbar setItems:[NSArray arrayWithObjects:infoButton,nil]];
//Add the toolbar as a subview to the navigation controller.
[self.navigationController.view addSubview:toolbar];
//Reload the table view
[self.tableView reloadData];
}
This results finally in the following screen (as i'd like to have it):
View iOS Mockup of current result
The Problem:
My Problem now is, that i can click ONLY on the Refresh Button. The other two buttons (Info and Logout) cannot be clicked. And i don't understand why? What I am doing wrong here?
Your help is kindly appreceated!
Try autoreleasing the second two buttons like your first one (the refresh).
UIBarButtonItem *myLogoutButton = [[[UIBarButtonItem alloc] initWithTitle:#"Logout" style:UIBarButtonSystemItemCancel target:self action:#selector(logout)]autorelease];
UIBarButtonItem *infoButton = [[[UIBarButtonItem alloc]
initWithTitle:#"Info" style:UIBarButtonItemStyleBordered target:self action:#selector(info_clicked:)]autorelease];
People, i have found the reason for my problem and i have to say, it was a very very silly one.
The first line of this project was responsible for all the troubels:
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 400)];
Since the View i created there is only sized 200x400, it is to small to recognize any events that appear in the outside of this view (although everything is visible).
If i change the size of this view, all works as expected:
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 500)];
But the more dynamic solution would probably be:
CGRect cgRect =[[UIScreen mainScreen] bounds];
CGSize cgSize = cgRect.size;
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, cgSize.width, cgSize.height)];
Maybe there is an even better solution for getting the dynamic screen size?
I want to add two Buttons on top of UIPopoverController like it is shown in following screenshots:
HTML Edit
Thanks for helping me!
Add your view controller to a UINavigationController, then add the Navigation Controller to the UIPopoverController. Then in your UIViewController's viewDidLoad method, put this code in:
UIBarButtonItem *okButton = [[UIBarButtonItem alloc] initWithTitle:#"Ok" style:UIBarButtonItemStyleBordered target:self action:#selector(okayButtonPressed)];
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:#"Cancel" style:UIBarButtonItemStyleBordered target:self action:#selector(cancelButtonPressed)];
self.navigationItem.title = #"My Title";
[self.navigationItem setLeftBarButtonItem:cancelButton animated:NO];
[self.navigationItem setRightBarButtonItem:okButton animated:NO];
[cancelButton release];
[okButton release];
You need to initialize your popover with a UINavigationController directly. Then set the root view to your custom view controller.
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:yourViewController];
UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:navigationController];
Use a UINavigationController as the pop-over. Then, access the .navigationBar property of the navigation controller, get the .topItem, and set its .leftBarButtonItem and .rightBarButtonItem.
I wouldnt use a navigationcontroller like the previous posters suggested, apple recommends not using navigationcontrollers on ipad (with good reason) it doesnt behave as youd expect when pushing VC into the stack when used in popovers, now you dont really want to use the "navigation" aspect of it, but i wouldnt use navigationcontroller just because uw ant the bar....Use a UIToolBar instead, and set its buttons to whatever you want...no need to use a navigation controller here...
When I do this my navBar doesn't seem to fit properly inside of the UIPopoverController, as shown in the below:
http://www.flickr.com/photos/coleorton/4752223066/
Here's what I'm doing:
// alloc the Direct Reports view controller.
ToolsViewController *toolsViewController = [[[ToolsViewController alloc] init] autorelease];
UINavigationController *toolsNavController = [[[UINavigationController alloc] initWithRootViewController:toolsViewController] autorelease];
toolsNavController.title = #"Tools";
toolsNavController.view.frame = CGRectMake(0.0, -10.0, 320.0, POPOVER_HEIGHT);
if(![self.toolsPopoverController isPopoverVisible]){
// show popover
self.toolsPopoverController = [[[UIPopoverController alloc] initWithContentViewController:toolsNavController] autorelease];
self.toolsPopoverController.delegate = self;
self.toolsPopoverController.popoverContentSize = CGSizeMake(320.0, POPOVER_HEIGHT);
[self.toolsPopoverController presentPopoverFromBarButtonItem:sender
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
} else {
// close popover
[self.toolsPopoverController dismissPopoverAnimated:YES];
}
This worked!
//Determine how to present this view based on device
if ([UIDevice currentDevice ].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
BNRAssetTypeViewController *contentViewController = [[BNRAssetTypeViewController alloc] init];
UINavigationController *popOverNavigation = [[UINavigationController alloc] initWithRootViewController:contentViewController];
self.assetPickerPopover = [[UIPopoverController alloc] initWithContentViewController:popOverNavigation];
[self.assetPickerPopover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
then in the init function of contentViewController add this
//add a barbutton item which will help in adding new type
UIBarButtonItem *bbi = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(addNew:)];
//set bar item to right side of navbarite
self.navigationItem.rightBarButtonItem =bbi ;
i am not sure what i am missing here. I Have a custom UINavigationController and i am trying to add a persistant UIBarButtonItem to the bar.
-(void)viewDidLoad
{
self.navigationBar.barStyle = UIBarStyleBlack;
UIBarButtonItem *bbi = [[UIBarButtonItem alloc] initWithTitle:#"Nope..."
style:UIBarButtonItemStyleBordered
target:self
action:#selector(goBack:)];
self.navigationItem.leftBarButtonItem =bbi;
[bbi release];
}
-(void)goBack:(id)sender
{
NSLog(#"go back now");
}
what am i missing here? - BTW, i do not want to/ will not use IB.
UPDATE:
Currently this is the closest i can get:
-(void)viewDidLoad
{
self.navigationBar.barStyle = UIBarStyleBlack;
UINavigationBar *navBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 20, 320, 44)];
navBar.barStyle = UIBarStyleBlack;
UINavigationItem *navItem = [[UINavigationItem alloc] initWithTitle:#"Currently Playing..."];
[navBar pushNavigationItem:navItem animated:NO];
UIBarButtonItem *editButton = [[UIBarButtonItem alloc] initWithTitle:#"Close" style:UIBarButtonItemStyleBordered target:self action:#selector(goBack:)];
navItem.rightBarButtonItem = editButton;
[self.view addSubview:navBar];
[editButton release];
[navItem release];
[navBar release];
[super viewDidLoad];
}
It's terrible i have to add an entire navbar to a UINavigationController that already has a navbar....if i try to use the existing, i get this error:
'NSInternalInconsistencyException', reason: 'Cannot call pushNavigationItem:animated: directly on a UINavigationBar managed by a controller.'
....really???
navigationItem must not be set on the UINavigationController instance but on the view controller of the view which is displayed "inside" the navigation controller.
Setting self.navigationItem on your navigation controller would work if your controller was itself pushed into another navigation controller.