iOS 8 UINavigationController disable Back Button - objective-c

in my Navigation Controller I need to temporarily disable the back button. I know that it can be hidden using the following or something similar:
[self.navigationController.navigationItem setHidesBackButton:YES animated:YES];
But that is not what I need, instead I want the back button to be greyed out and non-responsive to user touch events. Is their a way to achieve this without replacing the default back button?
Thanks in advance!

To disable the back button, these commands would make it do what you want it to do:
Enable:
self.navigationController.navigationBar.userInteractionEnabled = YES;
self.navigationController.navigationBar.tintColor = [UIColor blueColor];
Disabled:
self.navigationController.navigationBar.userInteractionEnabled = NO;
self.navigationController.navigationBar.tintColor = [UIColor lightGrayColor];
Update:
As of iOS 7, there's also a swipe that you'll want to disable on the UINavigationBar.
// You wrap it an 'if' statement so it doesn't crash
if ([self.navigationController respondsToSelector:#selector(interactivePopGestureRecognizer)]) {
// disable the interactivePopGestureRecognizer
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}

This hides the back button, so it becomes unreachable for the user. And it disables the swipe gesture.
[self.navigationItem setHidesBackButton:YES animated:YES];
Swift:
navigationItem.setHidesBackButton(true, animated: true)
See more info in Apple's documentation.

I know this is quite old but I had this problem too.
In my case in one scenario I had to disable the back button and in another one I had to disable all navigation buttons. my solution was disabling the navigation bar in total in both scenarios:
self.navigationController.view.userInteractionEnabled = NO;
This won't show the buttons as disabled but will prevent touches.
Hope this will help

I believe that following should help:
self.navigationController.navigationItem.backBarButtonItem.enabled = NO;
UPDATE
Sorry guys, my belief didn't come true.
It seems that property backBarButtonItem is designed only for setting custom title or image for Back Button.
From documentation:
If you want to specify a custom image or title for the back button,
you can assign a custom bar button item (with your custom title or
image) to this property instead. When configuring your bar button
item, do not assign a custom view to it; the navigation item ignores
custom views in the back bar button anyway.
The default value of this property is nil.
Unfortunately I didn't find any way of disabling back button with saving its native look and behaviour, because any time when I try to set custom UIBarButtonItem into navigationItem.backBarButtonItem property - it gets updated with appropriate native back button style and it always has enabled == YES.
I think this is done by Apple for a reason because we basically shouldn't force the user to stay on a detail screen and disable him from going back.
Also, in iOS7 and later user always can use swipe-from-left-edge gesture (if you don't disable it) to go back.
The only one ugly thing that I can recommend is to create a custom UIBarButtonItem and set it into leftBarButtonItem with 'Back' title, target and selector which will pop your viewController. By default it will substitute native back button.
Then you can disable it as usual using navigationItem.leftBarButtonItem.enabled = NO.
Unfortunately it will not look and act (in case of title updating depending on available space) as native back button :(

Just set a disabled back button on the navigation item of the previous view controller. Don't try to disable your custom back button if you already had one, won't work. Just set a new one which is disabled. You can reach the previous navigation item through the UINavigationBar.backItem property.
// set disabled back button
let backButton = UIBarButtonItem(title: "Back", style: UIBarButtonItem.Style.plain, target: nil, action: nil)
backButton.isEnabled = false
navigationController?.navigationBar.backItem?.backBarButtonItem = backButton
// disable pop gesture
navigationController?.interactivePopGestureRecognizer?.isEnabled = false

Related

backBarButtonItem with popViewController and swipe

My App logic is like that: VCA => VCB, and there is a scroll view in VCB with swipe left and right function. Some code help to understand structure, in VCB:
self.scrollView.pagingEnabled = YES;
self.scrollView.directionalLockEnabled = YES;
self.scrollView.contentSize =CGSizeMake(CGRectGetWidth(self.scrollView.frame) * numberPages, CGRectGetHeight(self.scrollView.frame));
so what I want is list some pages horizontally and swipe to left and right to navigate. Each page has it own view controller(child view controller of VCB) and I add them like that:
if (controller.view.superview == nil)
{
[self addChildViewController:controller];
[self.scrollView addSubview:controller.view];
[controller didMoveToParentViewController:self];
}
So far it works fine for iOS 6. I can swipe to change page. All function inside each page also works fine.
Then the problem comes with iOS 7's new feature, swipe to right to automatically call popViewControllerAnimated:, same effect like click go back button. To solve the conflict, I disable the interactivePopGestureRecognizer: self.navigationController.interactivePopGestureRecognizer.enabled = NO;
and it works ok, no force to pop back when I just want to swipe change the page.
Now the real problem. I set a back button(backBarButtonItem) on navigation bar. Every time I use that button pop from VCB back to VCA and current page is not the first page (that means there is at least one page on the left side), the pop animation is like first change page to the left side one, then immediately show VCA without any animation.
So any solution? Please help me.
First of all, it is hard to determine the problem without any piece of your code.
And secondly, why won't you create the button yourself, and add a target to it, a function that'll dismiss / pop the view controller?

iOS7 custom interactive transition, hidden back button reappears as "..." when cancelled

I have a custom interactive transition which requires me to hide the standard back button. Basically, the transition looks like a push from left-to-right rather than the standard right-to-left push we're all familiar with. That's why my back button is on the right side instead.
As you can see from two screenshots I took before and after cancelling pop transition activated by a UIScreenEdgePanGestureRecognizer, once the transition is cancelled there is a "..." where the back button would be.
I'm currently using
self.navigationItem.hidesBackButton = YES;
and I've tried putting it in awakeFromNib, viewDidLoad, viewDidAppear, viewWillAppear methods all without fixing the problem.
So using the power of Reveal.app I investigated the view hierarchy before and after and saw this:
What you see highlighted in each part of the image is what appears to be changing in the area of the nav bar that contains the hidden back button. Before it's a UINavigationButton and then it becomes a UINavigationButtonItem with a UILabel, which must be what contains the "..." and remains like this.
Any help would be much appreciated. I hope this is detailed enough to give a good picture of the issue.
Try creating an empty backbutton first (in the parent viewcontroller before the vc is pushed) - maybe that will prevent the "..." UILabel from being created.
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc]
initWithTitle:#""
style:UIBarButtonItemStyleBordered
target:nil
action:nil];
Another idea: Just set the parent vc title to an empty string.
self.title = #"";

UINavigationBar Back button with no text, ever

I have a requirement in a project that the UINavigationBar Back button should never have text in it, it should always just be a left arrow.
By default iOS is going to insert the title of the previous controller in there. Is there any way I can stop this from happening across the whole app?
(I know I can do this screen by screen, but I'm working on an existing app with A LOT of screens it and this would be a big job)
You can always set an image of an arrow to left bar button of navigation bar
// ADDING IMAGE TO BUTTON
UIButton *refreshButton = [UIButton buttonWithType:UIButtonTypeCustom];
[refreshButton setFrame:CGRectMake(0,0,30,30)];
[refreshButton setImage:[UIImage imageNamed:#"arrow_image.png"] forState:UIControlStateNormal];
refreshButton.userInteractionEnabled=NO;
// ASSIGNING THE BUTTON WITH IMAGE TO LEFT BAR BUTTON
UIBarButtonItem *refreshBarButton = [[[UIBarButtonItem alloc] initWithCustomView:refreshButton] autorelease];
self.navigationItem.leftBarButtonItem = refreshBarButton;
You will have to write this in each view controller in order to disable default left bar button.
You can't stop it from happening across the whole app, you'll have to set it manually in each controller. You could use a category on UIViewController and call that method in each controller, which will get you down to 1 line of code that doesn't have to change if you change your approach. Still sucks, I know. Also, you will probably have issues with Apple if you do that. We tried that in one of our apps and when I showed it to the Apple guys at WWDC '13 they flat out told me they would reject the app if I submitted it that way. YMMV

Problem with UISPlitViewController toolbar

I'm trying to use a toolbar in a splitviewcontroller. For some reasons that are unknown to me, the table view on the left is not resized correctly.
If I turn to portrait and open the table view from the toolbar item and then go back to landscape view, the tableview is then displayed properly. I'm not sure why this happens.
This is what I have in the RootViewController:
self.navigationController.toolbar.items = [NSArray arrayWithObjects:... nil]; // Setting these to an empty array doesn't change anything
self.navigationController.toolbarHidden = NO;
self.navigationController.toolbar.barStyle = UIBarStyleDefault;
I doubt the bug is there, but the complete source code is available on github if there's something obvious to check.
I moved the code into viewDidAppear and it now works as expected.

How to prevent manual zooming in a UIScrollView

Hopefully someone can help with this issue. I have a class derived from UIScrollView and I'd like to prevent the user from being able to zoom or scroll via manual pinch and swipe gestures. All view navigation will instead be controlled by programmatic means in response to where a user taps (think of an ebook reader where tapping on the left or right sides of the display causes the view to scroll by exactly one page width). Any suggestions on how to implement this?
On your - (void)viewDidLoad; you should be able to just disable whatever gesture recognizer you want. In this case:
UIPinchGestureRecognizer *pinchRecognizer = self.pinchGestureRecognizer;
pinchRecognizer.enabled = NO;
or
UIPanGestureRecognizer *panRecognizer = self.scrollView.panGestureRecognizer;
panRecognizer.enabled = NO;
I sometimes do this from view controllers that contain UIScrollViews. I just target the scroll view (self.scrollView.pinchGestureRecognizer) and temporarily disable gestures when the app. is in a certain state.
To prevent user-controller zooming and panning but still allow programmatic zooming and panning of a scrollview, the best approach is to override the UIScrollView's -addGestureRecognizer: method in a subclass.
In my use I wanted to block all the recognizers and control the viewable area completely from my view controller, I did so like this:
-(void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
//Prevent any of the default panning and zooming controls from working
gestureRecognizer.enabled = NO;
[super addGestureRecognizer:gestureRecognizer];
}
Each gesture recognizer is simply disabled, for finer control (allowing the pan control but only allow zooming via a double tap for instance) you'd simply check the incoming gesture recognizer via -isKindOfClass: and disabling as appropriate.
-(void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
//Prevent zooming but not panning
if ([gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]) {
gestureRecognizer.enabled = NO;
}
[super addGestureRecognizer:gestureRecognizer];
}
I used this method in a comic reading app that uses guided navigation to animate between cropped panels on a page with the full page being contained in a UIScrollView.I can smoothly zoom in and out on a selected area by simply setting the view bounds to the region I want to display.
A quick note here. It seems UIScrollView's panGestureRecognizer and pinchGestureRecognizer are both enabled the first time a view controller is added to a window.
Basically what that means is setting them to enabled = NO in viewDidLoad won't work in some cases. I moved my enabled = NO to viewWillAppear: and it stuck. :)
I don't have too much experience with UIScrollViews, but looking at the docs, it looks like you can set maximumZoomScale, minimumZoomScale, and scrollEnabled to disable everything you want to disable.
Here are the docs: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIScrollView_Class/Reference/UIScrollView.html
From the docs:
scrollEnabled:
If the value of this property is YES ,
scrolling is enabled, and if it is NO
, scrolling is disabled. The default
is YES.
When scrolling is disabled, the scroll
view does not accept touch events; it
forwards them up the responder chain.
maximumZoomScale:
This value determines how large the
content can be scaled. It must be
greater than the minimum zoom scale
for zooming to be enabled. The default
value is 1.0.
In your UIScrollView subclass overwrite also the setZoomScale: method which automatically re-disables the gesture
- (void)setZoomScale:(CGFloat)zoomScale {
[super setZoomScale:zoomScale];
self.pinchGestureRecognizer.enabled = NO;
}