Get title of backBarButtonItem - ios

I'm currently writing an app with multiple users.
I would like to use the same "Profile" view in storyboard to display info for all the users.
The plan was to set the title of the "Profile" view and then push it.
- (void) pushGeneralProfileViewFrom:(UIViewController *)target usernameAsTitleOfView:(NSString *)title {
UIViewController *myView = [target.storyboard instantiateViewControllerWithIdentifier:#"GeneralProfileView"]; // created in storyboard, Feed View
myView.title = title;
[target.navigationController pushViewController:myView animated:YES];
}
This worked great. However, the "profile" view also has buttons that lead it to other views in the storyboard. Those views also display specific info for the relevant user.
I was planning to use the name of the backBarButtonItem to know the user I need to display the info for. While I can see the back button with the username in the simulator, I'm unable to get it's self.navigationController.navigationItem.backBarButtonItem.title or self.navigationItem.backBarButtonItem.title. Both return null.
What am I doing wrong?
Also, I have a feeling this is not the best practice to handle those kind of things. I've searched the web and so far haven't seen a better way to pass values to a view I'm pushing. Suggestions?
Thank you.

The backBarButtonItem that you see when your view controller is visible in the navigation controller interface is not the backBarButtonItem of this view controller. It is the backBarButtonItem of the second view controller, the one behind this one in the stack.
So what you want is this:
UIInteger c = [self.navigationController.viewControllers count];
UIViewController* vc2 = [self.navigationController.viewControllers objectAtIndex:c-2];
Now get the backBarButtonItem of the navigationItem of that view controller. Or just get its title if they are the same.

Related

UISplitViewController: Programmatically Making Popover Controller Access Button Appear on Detail View

I don't know how to ask this more precisely. I have a master/detail and am creating the whole thing programmatically. I subclasses UISplitViewController and populated it with the two controllers, and everything looks as it should until I set splitViewController:shouldHideViewController:inOrientation such that it returns YES in portrait modes.
When I have the master hiding in portrait and portrait upside-down, as expected, it hides. However, I can't add a "Master" button to the nav bar at the top of the detail view in splitViewController:willHideViewController:withBarButtonItem:forPopoverController. This is probably because I have a fundamental misunderstanding of how I'm supposed to accomplish that task.
I followed the Apple examples and did:
barButtonItem.title = NSLocalizedString(#"Master", #"Master");
[detailController.navigationItem setLeftBarButtonItem:barButtonItem animated:YES];
I'm not getting any errors, but no button either. I speculate that perhaps it's because what I'm saving as detailController in my subclass is a UINavigationController and not a UIViewController.
Any guidance on this is much appreciated!
Having written this, I realized that there were several errors in wiring this whole thing up:
splitViewController:willHideViewController:withBarButtonItem:forPopoverController really wants you to not only to set the barButtonItem title, but also to add it to the nav bar of the detail controller.
If you ever want to programmatically dismiss the popover, you have to store the popover supplied in splitViewController:willHideViewController:withBarButtonItem:forPopoverController someplace in the master view.
So, the answer to the first part of the question was:
barButtonItem.title = NSLocalizedString(#"Master", #"Master");
[[detailController.topViewController navigationItem] setLeftBarButtonItem:barButtonItem animated:YES];
That got me to the UIViewController that can set a UIBarButtonItem on the navigation bar. I'm sure I could have done this directly on the UINavigationController but didn't immediately see how.
The second, unasked part of this question, deals with what to do with the popover once it's visible. Again, I needed the detail controller to know what the actual popover was so it can be dismissed, so in splitViewController:willHideViewController:withBarButtonItem:forPopoverController, I added code like:
[masterController.navigationItem topViewController].popoverController = pc;
where pc is the value of the argument passed into the delegate method. Then, in my master controller, I have a UITableView and on the didSelectRowAtIndexPath, I simply did this:
if(popoverController)
[popoverController dismissPopoverAnimated:YES];
And that's what I learned in iOS school today :)

Custom TabBarController functionality

I'm attempting to create a custom tab bar controller with the following options:
Feed
Map
New
Camera
Search
The feed, map, camera, and search will each pull up their individual VC's, while new is supposed to be more of a functionality button. When the new tab item is pressed, the map view should be displayed, and the map should begin recording the user's location. I'm trying to use a UITabBarController to manage these views, but I cannot seem to figure out how to implement the functionality that I would like with the "New" tab. It seems as if I would need to implement a separate view controller for the "New" record and stop functionality but that doesn't seem right.
The functionality of record/stop should be similar to snapchat's big red button that takes a picture when you press it.
While I agree with Scott's comment that this is a bad UX, if you technically wanted to do it, you could subclass UITabBarController and in viewDidLoad you could add a UIButton subview to the the tab bar controller's tabBar:
[self.tabBar addSubview:yourCustomButton];
Thus, this button could have it's own action and selector to do whatever you want with.
Take a look at idevrecipes for an example.
I think you have to implement the container view controller yourself. I think you can't do that with UITabBarController.
I was going to dig up the idevrecipes example that shawnwall pointed out, but there's another possibly answer, assuming you want the New button to match the standard UITabBarButton appearance. I agree it may not be the best UI, but it's workable.
For starters, you would create a dummy view controller for the New item. I'm not saying you should duplicate the Maps controller or anything, I'm just saying create an empty view controller and stash to it (or it's location) in a property. Assuming you're creating your tab bar in application:didFinishLaunchingWithOptions:, it'd look something like this.
self.newViewController = [[UIViewController alloc] init];
self.newViewController.title = NSLocalizedString(#"New", nil);
self.newViewController.image = [UIImage imageNamed:"new.png"];
Drop that view controller at the appropriate location in the tab bar controller's viewControllers property.
Save a reference to the Maps controller the same way you saved one for the dummy New controller.
If you haven't already done do, set the delegate of your tabBarController to your app delegate. You may need to declare that your app delegate conforms to UITabBarControllerDelegate.
UITabBarDelegate gives you a few hooks for tracking changes to the tab bar. tabBarController:shouldSelectViewController: looks to be the appropriate place for us to hook in for your desired behavior.
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
if ([viewController isEqual:self.newViewController]) {
self.tabBarController.selectedViewController = self.mapViewController;
// Whatever logic you need to start the recording
return NO;
}
return YES;
}
The look of the user interaction's a little odd - the user tabs the middle item (New), but the item to the left (Map) gets selected. If you want the "tab bar triggers behavior" action, I'd go the idevrecipes route and make the button visually distinct. If you're married to the tab bar item look, though, I believe this is how you'd accomplish it.

Push View Controller not showing elements added from storyboard

Okay, so far I've two view controllers in my storyboard. One with "login" elements and other as "User's home" sort of thing. I am intending to do the following : When user clicks on login, there's a bit of processing and then it should show to user's home screen..
When I do it via storyboard, i mean = control drag "login" button to user's home view it works fine. But I cant use that as I've to process the login data. It also shows some animation meanwhile. So, I've to do this shift programmatically. I wrote following code in the login button's IBAction ::
HomeViewController *homeView = [[HomeViewController alloc] init];
[self presentViewController:homeView animated:YES completion:NULL] ;
Now, this takes user to the intended view. However, the elements in the homeview (say a label, navigation bar are not being shown. And thats what my worry is.
(In theory, I can build entire view programatically but i think thats not the proper way of doing this, is it ? I want to make use of storyboard functionality in full i.e. design maximum UI in storyboard and use them from the backend how you want them to work.)
How do I do it ?
Cheers.
PS : I intend to add few more view controllers so at the moment i didn't think of navigation controller. not sure, if i should use it.
Using storyboards you should be using:
UIViewController *homeView = [self.storyboard instantiateViewControllerWithIdentifier:#"someID"];
[self presentViewController:homeView animated:YES completion:NULL] ;
Then set the ID to the view controller in storyboard like so:
Additionally, if you wish to there is absolutely nothing wrong with designing your UI entirely in code. Personally I prefer it. It gives you much more flexibility than interface builder.
In addition to NSPostWhenIdle's suggestion of instantiateViewControllerWithIdentifier, you can also define a segue between the two view controllers (not between the button and the second controller, but between the two view controllers):
Then give the segue a unique identifier, and then have your IBAction method do a performSegueWithIdentifier. This way your storyboard will continue to visually represent the various relationships between your view controllers.

iOS: Hide rootViewController of SplitView in TabBar app

I have a TabBar iPad app with a Split Controller in first tab. I follow this instructions to make it:
http://www.iphonedevsdk.com/forum/iphone-sdk-development/62217-simplest-way-make-split-controller-tab-bar-controller.html
Now my goal is to hide the root view controller of the split controller. I found a method to accomplish this:
http://vimeo.com/13054813
But that doesn't works for me, because it only works assuming the split controller is in the MainWindow.xib. But with the previous method, the split controller is added programatically.
Can someone help me to get my goal? Any idea would be appreciated.
Thanks in advance!
Here are the code:
http://dl.dropbox.com/u/27695108/MariCruz.zip
I hope you can help me.
Thanks!
You have a couple of problems with your project.
1 First one is that you are using a UITabBarController, that is why the code you found to hide the root view controller does not work.
Second one lays with your implementation of makeSplitViewController, where you are initializing twice your splitViewController, rootViewController, and detailViewController.
So, you have to fix point 2, so that you can correctly manage all of those controllers and then you should modify toggleSplitView so that you take into account the fact that you are using a UITabBarController. For example, replace the first few lines of that method with the following ones:
- (void)toggleSplitView {
NSArray *controllers = _tabBarController.viewControllers;
UIViewController* controller = [controllers objectAtIndex:1];
if (controller.view == splitViewController.view) {
[splitViewController.view removeFromSuperview];
splitViewController.viewControllers = [NSArray arrayWithObjects:rootViewController, rootViewController, nil];
splitViewController.view = detailViewController.view;
} else {
....
As you say, I am no accessing _window to check if the UISplit is there, because that view is not under _window, rather it is in the tab bar. The other branch of the if also needs to be rewritten according to the same criteria, but I will leave it for you.
The above code will work only with your second tab (the one corresponding to index 1); indeed, since you are overwriting splitViewController in makeSplitViewController, I can only use the element at index 1 in the tab bar without making further changes.

iOS: Setting text in nib subview from view in UITabBar/UINavigationController application

I'm having a problem getting a UISearchDisplay's text value to be set programatically on load of the view by another view and my question is have I overcomplicated my problem and missed something or am I on the right track of thinking.
Here's the situation: I have a UITabBarController as my root view, there are 2 tabs, both have a UINavigationController setup so I can push views as needed.
Tab 1 has a UITableViewController which is populated with a list of categories.
Tab 2 has a MapView in it's main view but I have done a custom UINavigationItem view to put various buttons and a UISearchDisplay on the rightBarButtonitem area.
The mapview layout and custom navigation item are stored in the same nib as two separate view objects. In Tab 2's viewDidLoad(), I initialise the rightBarButtonItem programatically with:
UIBarButtonItem *btnItem = [[UIBarButtonItem alloc] initWithCustomView:buttonBar];
self.navigationItem.rightBarButtonItem = btnItem;
[btnItem release];
Everything fires up, buttonBar is wired up to an IBOutlet as searchWhat and I can talk to this object from within the mapview's controller class.
If the user is in Tab 1 and taps a cell, I want it to switch to Tab 2 and populate the searchWhat.text and then execute the search code as if someone had typed in the search themselves.
What i'm having trouble with is the order of load and populate on a view.
I can access the 2nd tab from the 1st without any problem and get it to appear with something like:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Quick Category cell tapped at row %d", indexPath.row);
self.tabBarController.selectedIndex = 1; // change to the search view controller
//[self.tabBarController.selectedViewController viewDidAppear:YES];
UINavigationController *nav = (UINavigationController *)self.tabBarController.selectedViewController;
SearchViewController *srch = [nav.viewControllers objectAtIndex:0];
//NSLog(#"%#", [srch description]);
[srch queueSearchByType:kSearchTypeQuickCategories withData:[catList objectAtIndex:indexPath.row]];
[srch viewDidAppear:YES];
}
Don't worry about catList and SearchViewController, they exist and this bit works to switch tabs.
Here's the problem though, if the user starts the application and selects an item in tab 1, tab 2 appears but the values of the search display text don't get set - because viewDidLoad and viewDidAppear are called in another thread so the execution of queueSearchByType:withData: gets called while the view is still loading and setting up.
If the user selects tab 2 (therefore initialising the subview) and then selects tab 1 and an item, it can populate the search display text.
I can't just change the order of the tabs so that tab2 is first and therefore loads it's subviews to the navigation bar as the project specification is category search first.
Have I missed something very simple? What I need to do is wait for the second tab to fully appear before calling queueSearchByType:withData: - is there a way to do this?
At the moment, i've implemented a queue the search, check for a queue search approach, this seems to be a bit long winded.
Ok, I don't like answering my own question but it appears my fears were right, basically if you want a UINavigationItem that is a custom view (ie, to put a search bar and various other buttons up on the nav controller) and be able to switch to and populate them from another tab on a tab bar controller, then you need to put the subview in it's own class which is a subclass of UIViewController and then make delegation your friend (which it already is), i've provided an example in case anybody needs to repeat it which i've put on my blog HERE.
http://www.jamesrbrindle.com/developer/ios-developer/howto-add-a-custom-uinavigationitem-to-a-uinavigationcontroller-with-delegation.htm
If anyone disagrees and thinks this can be simpler, please let me know or rate this post

Resources