I am an iOS development newbie. I am using the following code to set my backBarButtonItem -
UIBarButtonItem *temporaryBarButtonItem=[[UIBarButtonItem alloc] init];
temporaryBarButtonItem.title=#"Back";
self.navigationItem.backBarButtonItem = temporaryBarButtonItem;
[temporaryBarButtonItem release];
I also want it to execute another function, apart from going back. Is that possible? Or do I need another button to save?
You can practically do that in your viewDidDisappear or viewWillDisappear method.
If this view can only go back and doesn't present any views, then this should work.
However, if you plan on presenting a subview, modal view, go deeper in the navigation hierarchy, or do other view operations that will cause viewDidDisapper to get called, then you'll need to separate your back-button code logic somehow.
For instance if you will present a modal view from this view, you can check if self.modalViewController is nil, if it is then you have no modal view being present and can safely execute the back-button code. If it is not nil then you have a modal view present and should not execute back-button code. (viewWillDisappear should register the modal view controller as not-nil).
Very simple, try this!
[[UIBarButtonItem alloc] initWithTitle:#"Done" style:UIBarButtonItemStyleDone target:self action:#selector(myCoolAction:)];
Then all you do is change myCoolAction: to an appropriate method in your view controller and handle it. Enjoy!
EDIT: Oh, if you want to use this for the backBarButtonItem, it won't work how you expect. The system will not call your target/actions for the backBarButtonItem. They get cleared once assigned to the backBarButtonItem.
One way to handle this is too hook up the your UINavigationController as a delegate. Then in your
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
Method you can do some custom behavior there.
Strictly speaking, this cannot be done with UIKit.
See the docs on backBarButtonItem:
The target and action of the back bar button item you set should be
nil. The default value is a bar button item displaying the navigation
item’s title.
The work around is to specify a leftBarButtonItem and attach whatever custom behaviour you require by attaching a #selector target.
The tricky bit is the button's image itself. As you know the default is not a rectangular button. Rather it has a left side arrow shape. For this you'll need to set a custom image to make the button appear to be the default.
There's tons of resources to do that out there including this one to extract all the UIKit artwork:
https://github.com/0xced/UIKit-Artwork-Extractor
You can add UIBarButtonItem in xib and add handler event there.
Else create UIBarButtonItem with a custom view, which is an UIButton and add event handler.
You should be able to do something like this instead of using viewDidDisappear or viewWillDisappear.
Place this in viewDidLoad:
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Cancel" style:UIBarButtonItemStyleDone target:self action:#selector(cancelButtonAction:)];
self.navigationItem.leftItemsSupplementBackButton = NO;
Then you can create the method cancelButtonAction cancelButtonAction for your custom code and the back functionality like this:
- (void)cancelButtonAction:(id)sender {
//Your custom code goes here...
//This will perform the back functionality if using a Navigation Controller
[self.navigationController popViewControllerAnimated:YES];
}
Note: this will end up using a rectangular button, without the arrow.
Related
On my side menu I call a NavigationController for each item on didSelectRowAtIndexPath.
Because of that I have a few NavigationControllers. So I created a custom UINavigationController to reuse the code.
The thing is that my UINavigationController subclass is being called but nothing appears on the simulator.
[self.sideMenuViewController setContentViewController:[self.storyboard instantiateViewControllerWithIdentifier:#"EventsXib"]];
EventsXib is my CustomNavigationController
Any idea?
For the record, the whole point for me to do this is that I want the same leftBarButtonItem and 2 rightBarButtonItems on all my ViewControllers.
UPDATED:
I noticed that this actually worked:
self.navigationItem.leftBarButtonItem = self.navigationController.navigationItem.leftBarButtonItem;
self.navigationItem.rightBarButtonItems = self.navigationController.navigationItem.rightBarButtonItems;
But I still have to do this in every viewController, and thats not what I want.
Here is a general idea of what it looks like:
As #GoGreen suggested, I created a base view controller with the corresponding buttons on the navigationItem.
Its not the simple solution I had in my mind but it works pretty good.
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.
I have a UINavigationController and am using the toolbar in one of my view controllers. I have several UIBarButtonItems. At various points, I disable certain buttons in the toolbar, using things like _btnEdit.enabled = NO.
This all works well except for one time where this happens when there is no user interaction. In that case, the button appears to be enabled (isn't grayed out), but doesn't accept touches. If I cover the bar with something (an action sheet from the bottom) or change the orientation of the device, it shows correctly.
I've tried self.navigationController.toolbar setNeedsDisplay] and [self.navigationController.toolbar drawRect:self.navigationController.toolbar.bounds] but neither have an any effect.
Any ideas on how to "refresh" this view? I know UIBarButtonItems don't inherit from UIView, which I feel like may be contributing to the issue.
This is the intended behaviour. The setNeedsDisplay is a good reflex try, but you don't own the navigation bar and UIBarButtonItem doesn't inherit from UIView, so we need to think of them a little differently.
Here how you can achieve your goal :
UIBarButtonItem *bbi = self.navigationItem.rightBarButtonItem;
bbi.enabled = NO;
[self.navigationItem setRightBarButtonItem:bbi animated:YES];
NOTE : self is a UIViewController
I've just made a quick test with this and it's working.
I have an application with a navigation bar that pushes to a login screen view controller and then pushes to a main menu. Is there any way I can remove the back button off the main menu, so the user is unable to go back to the login screen?
Thanks!
EDIT: Using Xcode 4.3 and doing all the leg work programmatically.
You can do:
[self.navigationItem setHidesBackButton:YES];
In your second view controller (the one you want to hide the button in).
Peters answer is correct, although I think the better question is why? In a schema like yours where you are wanting to login a user, instead of using a Pushed VC, present a Modal VC and use a delegate method to get back the userinfo that was obtained in the Login process. I can post a complete code example if you need it, but it sounds like you have the details worked out with your login process. Just use:
presentModalViewController
instead of:
pushViewController
That way, you don't have to worry about the navigation stack and doing something that isn't really in-line with the user interface guidelines.
In swift
self.navigationItem.hidesBackButton = true
The above code did not work for me. As suggested in UINavigationItem setHidesBackButton:YES won't prevent from going back,
I had to use:
[self.navigationItem setLeftBarButtonItem:[[UIBarButtonItem alloc] initWithCustomView:[[UIView alloc] init]]];
Try this:
[self.navigationItem setHidesBackButton:YES];
Or
[self.navigationItem setHidesBackButton:YES animated:YES];
Tried in Xcode7.3.1, swift
self.navigationItem.setHidesBackButton(true, animated: true)
It only hide the back arrow and disabled the back action, but I can still see the name of the previous view controller.
For those who want to also hide the name of the previous view controller, try Yoga's answer works for me. In swift
self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: UIView())
In the case you need to toggle show/hide the back button:
navigationItem.hidesBackButton = true/false
And keep the swipe back gesture:
extension YourViewController: UIGestureRecognizerDelegate {}
And
navigationController?.interactivePopGestureRecognizer?.isEnabled = true
navigationController?.interactivePopGestureRecognizer?.delegate = self
I have a UIViewController classes A and B. A loads B using: [A.view addSubView B.view].
B has a navigation bar with a Back button. I want to go back to A when I click it, so in the selector I tried [self.view removeFromSuperview], but it only removed the navigation bar. Then I tried [self.view.superview removeFromSuperview], it still just removed the navigation bar. What should I do?
Also, another minor issue with the Back button: setting it's title. I tried these two ways, but it still displays "Back".
navItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Chapter" style:UIBarButtonItemStylePlain target:self action:#selector(handleBackBarButtonItem:)];
navItem.backBarButtonItem.title = #"Chapter";
Thank you in advance!
I don't think you quite understand how navigation (with UINavigationController) works in iOS. Assuming you want animation, this is what you want:
Set up a UINavigationController. This can be done in the app's delegate (to avoid memory leakage, set an instance variable on UINavigationController *navController:
navController = [[UINavigationController alloc] initWithRootViewController:A];
Note that we are adding A as our root view controller.
Push the second view controller when needed. I assume that you are adding B.view after a button is clicked or something. In the implementation of the method that adds the second view controller, run the following code, instead of [A.view addSubview:B.view]. This method should be in the first controller's .m file:
[self.navigationController pushViewController:B animated:YES];
This will also give a nice transition effect.
Pop the second view controller off the stack. With UINavigationController, a pretty arrow-shaped back button is automatically included in a pushed view controller, to navigate back to the last view controller. This means that you don't even need any code to allow backward navigation.
That's it! Now if you need to change the title of B's back button, do this in A's viewDidLoad method:
self.navigationItem.backBarButtonItem = customBackButtonItem;
You can get an array of subviews and then remove the ones you wanted to be removed. This SO post will show you how to remove all subviews or multiple subviews using subviews array.