UIBarButtonItem not disabled until view changes - ios

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.

Related

Pressing back button (backBarButtonItem) in KIF?

Does KIF provide any special support for tapping back buttons or will I have to do something like this?
// in parent ViewController
self.navigationItem.backBarButtonItem.isAccessibilityElement = YES;
self.navigationItem.backBarButtonItem.accessibilityLabel = #"Back";
// in test class
[tester tapViewWithAccessibilityLabel: #"Back"]];
The latter would be a bit unfortunate, because my code currently does not have back buttons at all and self.navigationItem.backBarButtonItem is and can normally remain nil (see here): the description in the storyboard suffices so far.
By default, the back button will be labeled "Back" and accessible to VoiceOver as such as well so:
[tester tapViewWithAccessibilityLabel: #"Back"];
will work if you haven't done anything else.
So assuming I understand the structure of your view controllers (which is navigation, but with no explicit backBarButtonItem set), then what you have should work without the parent view controller changes you're worried about.

iOS: Scope bar hidden when search bar is displayed in navigation bar

I'm trying to get a search bar and it's scope in the navigation bar, as the way the view first appears. If you simply drag a UISearchBar onto you table view controller in interface builder, it's placed in your table like a header cell. Then, when you tap it, it animates into the formation I'm after below. The problem is I want it to start out this way without any tapping, with a back button on the left and no cancel button on the right:
So, to give the search bar immediate focus without tapping, I tried adding [_searchBar becomeFirstResponder]; in viewDidLoad which doesn't work. Next I tried:
self.searchDisplayController.displaysSearchBarInNavigationBar = YES;
The search bar will indeed display in the navigation bar but the scope bar is gone, (WHY APPLE WHY) and there is an awkward gap.
I've also tried subclassing UINavigationBar and making it taller. It's easy to change it's size but the contents align at the bottom of the bar and overlap anything you try to add to it.
So to re-iterate, I need the search bar to display in the navigation bar with a scope control when the view first appears, without any tapping by the user. I should also specify that this is on a UITableViewController (because the page has a UIRefreshConrol), so simply dropping a toolbar in above the table view isn't an option. Thanks.
tl;dr: Don't.
You should know that adding a UISearchBar to the headerView of a UITableView invokes some custom code within UIKit that facilitates hiding the scope bar on start. While it used to be easier to show the scope bar all the time in iOS 6 and older, iOS 7 has changed this.
Your first approach, to becomeFirstResponder in viewDidLoad was a good idea, but this method is called after the view has been loaded into memory (such as out of a NIB). The view has not yet been added to the view hierarchy, so it can't become the first responder. viewDidAppear: is called right after the view is loaded into the view hierarchy, and a becomeFirstResponder does in fact allow the UISearchBar to receive focus.
The scope bar itself is a hidden (by default) subview of UISearchBar. You technically could just cycle through subviews and set it to not be hidden:
- (void)viewDidLoad
{
[super viewDidLoad];
[self recurseSubviewsForView:self.searchDisplayController.searchBar];
}
- (void)recurseSubviewsForView:(UIView *)view
{
for (UIView *subview in view.subviews) {
if ((CGRectGetMinY(subview.frame) == CGRectGetMaxY(self.searchDisplayController.searchBar.frame)) && subview.hidden) {
subview.hidden = NO;
self.searchDisplayController.searchBar.showsScopeBar = YES;
[self.searchDisplayController.searchBar sizeToFit];
}
[self recurseSubviewsForView:subview];
}
}
This is generally a bad idea. There's a basic check to see that the subview being targeted is the subview containing the scope bar, but that could break any second, might not be backwards compatible, etc.
The real question you have to ask yourself is why do I want the scope bar to always be visible? The way it works now, the scope bar will animate visible when the user taps into the search field and hide itself when the search field no longer has the focus. Even with the "hack" above, the search bar gets the focus as soon as the user taps a scope button. What's the point of showing a search option when search isn't even active? When in doubt, fall back to Apple's suggestions. It will make your life a lot easier in the long run, and probably make your app look and behave better. Apple didn't just add that interaction on a whim. They tested it like crazy. That's why it's so hard to make it work another way. That's why there's special code run when a UISearchBar is the headerView of a UITableView...because it's likely better for the user.
In addition, I see your screenshot targeting iOS 8, but your code snipped shows using a UISearchDisplayController. This paradigm has been deprecated in favor of UISearchController. Please consider updating.

UIBarButtonItem clickable on left but not on right of navigation controller

This is really strange behavior and I'm only experiencing it in iOS8 iPads. I have a UIBarButtonItem that needs to go on the right side of the navigation bar. Here is my code to set the button:
UIBarButtonItem *btnAttOpen = [[UIBarButtonItem alloc] init];
[btnAttOpen setAction:#selector(addAttClick:)];
[btnAttOpen setImage:[UIImage imageNamed:#"addAtt"]];
[btnAttOpen setTarget:self];
[self.navigationItem setRightBarButtonItem:btnAttOpen];
When I do this, the btnAttOpen button appears where it should but is not clickable. It simply behaves as if it were a static image. The strangest part of this is if I replace setRightBarButtonItem: with setLeftBarButtonItem: the button behaves as intended.
This doesn't make sense to me. Has anyone seen this kind of behavior? Any ideas as to why this may be occurring? Thanks!
If something doesn't want to react appropriately to touches, often the problem is that one of the parent view's frames has incorrect size, which doesn't fully cover the child's frame.
You could check them, for example, by printing out view hierarchy in gdb: po [[UIWindow keyWindow] recursiveDescription]

IOS7: Pop ViewController forces the UIImageView to drop

After upgrading my project to iOS7
when I do a BACK Button and the UINavigationController goes back to the previous page, an ImageView on the top of the screen shifts down.
I use IB to do my layouts. These are my Simulated Metrics:
I have AutoLayout off. Any ideas on what the issue might be? I wasnt sure if anyone wants to see specific code and I didnt want to clutter up the question with too much code.
Updates: Based on the comment questions, I wanted to make these updates:
In no place in the application .h or .m file do I make any changes to the imageview's sizes or location.
In both the viewDidLoad and viewDidAppear I call a user-defined method called recalculateAll but their is no reference at all to any imageview sizes. Just for trying it out I commented out the entire section and ran the code and it still jumps down.
In my init I do programatically set some imageviews (you see the #132 in what appears to be a bubble) using their x and y's.
Here is a typical navigation I use for moving from the view controller to the tableviewcontroller:
GetTimeOffByType *showTimeOffReport = [[GetTimeOffByType alloc] initWithNibName:#"GetTimeOffByType" bundle:nil];
showTimeOffReport.timeOffType = #"Vacation";
[self.navigationController pushViewController:showTimeOffReport animated:YES];
These are all .xib files, no storyboarding at all. Its basically a view controller which has an embedded UINavigationController with 6 buttons. Each time a button is pressed it pushes a UITableViewController passing different parameters and showing different data. The transition I am using to get back to the original UIViewController is simply the iOS generated BACK button (so no code to show for that)
Update#2 Hopefully this will help someone solve this wierd behavior. So if I were to click on the table view cell on showTimeOffReport to get the cell detail and then using BACK navigate all the way back it doesnt jump down.
Update#3 Ok this is something I just discovered : The issue of jumping down or not is related to the translucency of the UINavigationBar. If you have a Translucent = YES it will start from the top of the window. If you have a translucent = NO it will start from the bottom of the UINavigationBar.
You might try setting the new property on UIViewController edgesForExtendedLayout to UIRectEdgeNone.
Here is a good resource that explains more about how view layouts changed in iOS 7.
See Apple Documentation
If you plan to be backwards compatible you will probably need to do some runtime checks and adjust positioning if the device is not running iOS 7.
This might help you..You can try adding UIViewControllerBasedStatusBarAppearance key and set it's value NO in your info.plist
UIViewControllerBasedStatusBarAppearance = NO

Add image UIBarItem to UINavigationController or alternative

I have a UINavigationController with a left and a right button on an app being used as a remote control for a piece of hardware. I would like to show that the hardware is connected to the app by displaying an icon in the navigation bar to the left of the right button. From the documentation it looks as though I can only add UIBarButtonItems which make me suspect there is another, more conventional place for my 'connected LED' indicator.
So my question is can I display an icon in a UINavigationController navigation bar and if not where should I display it?
UINavigationBar is a subclass of UIView, so you can add items to it like this:
[navBar addSubview:whatever];
The navigation bar is a property of the navigation controller (i.e. you can reference it like this self.navigationController.navigationBar).
There isn't really a "conventional place" for something like this. :)
I suspect this 'connected LED' should be displayed on all views, regardless of the current view (and its UINavigationItem). If that is correct, the easiest way would probably be to NOT put that icon in the actual UINavigationBar, but place it as a separate UIView in the UINavigationBar's superview.
you should be able to just create a uiview programatically and add it as a subview of the navbar
UIImageView *connectedView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"connected-icon.png"]];
[self.navigationController.navigationBar insertSubview:connectedView atIndex:0];
[connectedView release];
if insertSubview doesn't work as you expect try addSubview:
[self.navigationController.navigationBar addSubview:connectedView];
You probably want to create the connectedView as a property though so you can (more) easily remove it when you are no longer "connected".
see this other examples of the approach
try this code
[[[yourViewController viewControllers] lastObject] navigationItem].titleView = yourImageView;
worke for me in customising navigation bar in mail controller. Hope you get some idea from here.

Resources