When my app enters the background, my modally presented view controller dismisses an alert view like so...
// called when view controller receives a UIApplicationDidEnterBackgroundNotification
- (void)applicationDidEnterBackground:(NSNotification *)notification
{
if (self.alertView) {
[self.alertView dismissWithClickedButtonIndex:0 animated:NO];
self.alertView = nil;
}
}
When my app returns to the foreground without having been terminated, the alert view is gone. However, the bar button items in the navigation bar (from a UINavigationController) are still dimmed as if the alert view were still displayed.
Moreover, dismissing the modal view controller (by tapping a dimmed bar button item) reveals that the bar button items for the presenting view controller are also dimmed. The bar buttons items are functional, but they remain dimmed.
So how do I un-dim the bar button items? Or, how do I properly dismiss an alert view programmatically in iOS 7 in response to the app entering the background?
The iOS 7 UI Transition Guide states the following:
When an alert or action sheet appears, iOS 7 automatically dims the tint color of the views behind it. To respond to this color change, a custom view subclass that uses tintColor in its rendering should override tintColorDidChange to refresh the rendering when appropriate.
My navigation bars and bar button items are not custom views; I did not subclass them. I created the navigation bars in storyboard with their default attributes (same with the bar button items). So there's no place for me to override tintColorDidChange.
All of my views use the default value for their tintColor property.
I have tried re-seting the tint color to the default value without success:
if (self.alertView) {
[self.alertView dismissWithClickedButtonIndex:0 animated:NO];
self.view.tintColor = nil;
self.view.window.tintColor = nil;
self.alertView = nil;
}
I have also tried re-seting the tint color in the view controller's viewDidAppear: without success.
I also tried setting the main view's tintAdjustmentMode to "normal" without success:
if (self.alertView) {
[self.alertView dismissWithClickedButtonIndex:0 animated:NO];
self.alertView = nil;
self.view.tintAdjustmentMode = UIViewTintAdjustmentModeNormal;
}
By the way, if the the app was terminated while in the background, the app relaunches with the bar button items having the correct tint (i.e., un-dimmed).
I'm pretty sure this is a bug on Apple's end. I've filed a bug report at https://bugreport.apple.com, please file a duplicate bug report to get Apple to pay attention to it, as that is how Apple assigns priority to bugs.
I experienced the same bug in my app and successfully found a workaround. All you need to do is set tintAdjustmentMode to UIViewTintAdjustmentModeNormal on your application's main window after the UIAlertView is dismissed in background. Easy :)
Although I can dismiss an alert view programmatically in response to a UIApplicationDidEnterBackgroundNotification, the automatic tint-dimming in iOS 7 will not get updated.
However, the automatic tint-dimming behavior will respond if I dismiss the alert view in response to a UIApplicationWillResignActiveNotification instead.
// called when view controller receives a UIApplicationWillResignActiveNotification
- (void)applicationWillResignActiveNotification:(NSNotification *)notification
{
if (self.alertView) {
[self.alertView dismissWithClickedButtonIndex:0 animated:NO];
self.alertView = nil;
}
}
Related
I am using a UIView item on my view controller that contains a picker view and a button, which needs to appear on the screen only when the show button is clicked.
I created a outlet for my UIView with name *pickerView
The default position of this view (on the right properties bar of Xcode) is (0,200,320,261) for (x,y, height and width) which basically makes it appear at the base of the ViewController.
What I did for this view to hide initially when the view controller loads is, in the ViewDidLoad method I put this code:
pickerView.frame=CGRectMake(0,450,320,261);
For the action of show button,
pickerView.frame=CGRectMake(0,200,320,261);
I have a hide button inside this UIView, in its action i have
pickerView.frame=CGRectMake(0,450,320,261);
SO, from what I expect when I run the application, the UIView pickerView should initially hide because of code in viewDidLoad, and show button should bring it on the screen.
My problem is show and hide button works fine, but every time I load this ViewController the View appears on screen by default. Help me hide this UIView when I load the viewController.
Simpley don't set the frame for picker view
i am posting a sample code it makes picker view hide and appear when tapping the button
i am using the property "hide"
hear is the sample code
- (void)viewDidLoad
{
[super viewDidLoad // Do any additional setup after loading the view, typically from a nib.
//as simple dont set frame.
// i am using xib from there i wired up picker view
self.myPickerView.hidden = YES; //just hide it whenever you dont use it.
}
- (IBAction)whenShowHideButtonTapped:(id)sender
{
//when button pressed just show it
if(self.myPickerView.hidden)
{
self.myPickerView.hidden = NO;
}
else
{
self.myPickerView.hidden = YES;
}
}
hope this helps .. :)
You could call the hide code in 'viewWillAppear:' like this:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self hidePicker];
}
I am working on storyboard based application (iPhone). Application has a Navigation Controller to start with. We are integrating an existing application with it. Thus we need to load the NIB file on click of a button.
NSBundle *someBundle = [NSBundle category_bundle ];
MainWindow *aViewController = [[MainWindow alloc]
initWithNibName:nibName
bundle:someBundle];
[self.navigationController pushViewController:aViewController animated:YES];
The existing application then loads another VC.
[[self navigationController] pushViewController:mySecondView animated:YES];
This view again comes from NIB.
This view then uses a singelton to get the instance of MainWindow (loaded in first step) and request it to show a modal view. "Bad Design" but I can not change it as this is an existing application and I need to deliver the integration tomorrow.
Modal is shown as -
[self presentModalViewController:aModal animated:YES];
We are opening the modal in landscape and for that in its viewWillAppear we are using this code-
[UIApplication sharedApplication].statusBarOrientation = self.interfaceOrientation;
and in viewDidDisappear
if (SYSTEM_VERSION_LESS_THAN(#"5.0")) {
[UIApplication sharedApplication].statusBarOrientation = self.parentViewController.interfaceOrientation;
} else {
[UIApplication sharedApplication].statusBarOrientation = self.presentingViewController.interfaceOrientation;
}
Question:
The problem is that UIView of MainWindow moves up by 20px after the modal pop up has been closed. I have tried to reset the frame. Also tried to hide the status bar but then status bar partially hides the navigation bar, to resolve this we tried to hide the navigation bar after the status bar has been made visible and then showing it again, but with no success.
Please let me know how can I resolve this issue.
ok, i cant find the method called by UIViewController that presents a new view.
i have an app based on UINavigationController. Once i come to a view showing details of the object, i have 1 toolBar at the bottom so i can give some options to user.
When he press on barButtomItem, i want to show a new view but not changing the navigationbar, so if i press back button he goes back from detail view and not from new option.
i know method pushViewController but does not work as i want.
thx in advance!
edit: just to be a more bit more clear if i call
[[self navigationController]pushViewController:loteCompraViewController animated:YES];
i get a new view, related to the new controller but it also changes the navigationbar and that is not good for me.
Give your view controller of the "view showing details of the object" two methods: isShowingOverlayView and dismissOverlayView. In isShowingOverlayView, return YES if you're showing the "new view" because "he press on barButtomItem". In dismissOverlayView, hide the "new view".
Then make your own subclass of UINavigationController. In your subclass, override popViewControllerAnimated: to use those methods of your object-detail view controller, like this:
- (UIViewController *)popViewControllerAnimated:(BOOL)animated
{
if ([self.topViewController respondsToSelector:#selector(isShowingOverlayView)]
&& [(id)self.topViewController isShowingOverlayView])
{
[(id)self.topViewController dismissOverlayView];
return nil;
} else {
return [super popViewControllerAnimated:YES];
}
}
Use this subclass instead of the standard UINavigationController.
So I have a modal view displaying in my app that has a little info for the user to fill out. The problem is that when the device is rotated, some animation occurs, but only in the frame. The form itself does not rotate. All the autorotate options are set to YES. I am displaying it when the user clicks on a field in a popover. This makes me suspect it has something to do with that but I am not sure. It is bizzare because if the device is in either view and then the modal window is displayed, it is fine. It only happens when the device is rotated in the modal view. Does anyone have any idea what may be causing this behavior when the device is rotated? Thanks!
Here is a snippet that is handled in the popover view controller:
if (currentLevel == 1 && businessOrLocation == 0){
if(tbsViewController == nil)
tbsViewController = [[BusinessFilteredViewController alloc] initWithNibName:#"BusinessFilteredView" bundle:[NSBundle mainBundle]];
NSMutableArray *tempBusiness = [[NSMutableArray alloc] init];
for (id theKey in appDelegate.groupedBusiness) {
NSMutableArray *tempArr = [appDelegate.groupedBusiness objectForKey:theKey];
[tempBusiness addObject:tempArr];
}
tbsViewController.businessOrLocation = businessOrLocation;
tbsViewController.modalPresentationStyle = UIModalPresentationFullScreen;
tbsViewController.modalTransitionStyle = UIModalPresentationFullScreen;
[self presentModalViewController:tbsViewController animated:YES];
}
I ran into this problem as well. The fundamental problem is that popover controllers cannot present modal views—it seems that case wasn’t properly considered or designed for. In my situation, it was easy enough to work around. I just extended the delegate protocol for my popover-hosted view controller. The main view sets itself up as the delegate to the popover view, and takes responsibility for displaying and dismissing the modal views the user requests from within the popover.
Since I already had a delegate protocol to cleanly dismiss the popover view when the user clicks “done” it was only a small stretch to get autorotation working the way I wanted it to. Here are some snippets:
#protocol InfoViewControllerDelegate <NSObject>
#optional
// Implement this to close the info view once the user clicks done.
- (void)infoViewDidFinish:(InfoViewController *)view;
// Implement this method if the delegate launched us as a popup view and must therefore
// take responsibility for diplaying help.
- (void)infoViewDidRequestHelp:(InfoViewController *)view;
#end
And in my main iPad view which presents this popup view:
#pragma mark - InfoViewControllerDelegate methods
- (void)infoViewDidFinish:(InfoViewController *)view {
[self hideInfo:self];
}
- (void)infoViewDidRequestHelp:(InfoViewController *)view {
[self hideInfo:self]; // Close the info view first
HelpViewController *help = [[HelpViewController alloc] init];
help.delegate = self;
[self presentModalViewController:help animated:YES];
[help release];
}
To make life simple for cases where I am launching the info view outside of a popup view (for example, on the iPhone, it is a simple modal view), it checks to see if the delegate handles the modal subviews, and if not, handles them itself. That way I didn’t need to change the iPhone base controller at all, since autorotation already worked fine there. Here’s the “Help” button action in the info view controller, showing how I did that:
- (IBAction)help:(id)sender {
if ([delegate respondsToSelector:#selector(infoViewDidRequestHelp:)]) {
[delegate infoViewDidRequestHelp:self];
} else {
HelpViewController *help = [[HelpViewController alloc] init];
help.delegate = self;
[self presentModalViewController:help animated:YES];
[help release];
}
}
With this code in place, my entire interface autorotates smoothly on both devices, whether or not popup views were involved.
Just so i understand correctly... You are displaying a popover and inside that popover if the user taps a certain element then you are displaying a full screen modal view controller? Vie never tried that before and it seems odd for two reasons.
First it seems jarring to the user in my opinion. The popover gives you a nice, integrated UI and the modal takes you away.
More importantly though, your popover view controller doesn't really have authority over the whole screen so presenting a full screen modal from a popover just seems inherently wrong.
I would suggest you display a nav controller in the popover controller and instead of presenting the new view controller modally over the whole screen just push it on to the nav controller in the popover and keep the user inside the popover.
If that doesn't really work for you, then I would suggest reviewing your UI needs and redesigning the layout.
I am guessing that you implemented - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation in BusinessFilteredViewController and returns YES
Could you check that you add more than 1 subviews to application window . If so, try to create container UIViewController for all viewControllers that you want to add to window.
I have an iPhone app that is based on a navigation controller.
I have a main view controller that displays a list of articles, and a detail view, where you can see one article in a UIWebView. For the detail view, I have the navigation bar on the top, and a UIToolbar on the bottom.
I'd like to auto-hide them with a slide animation (to top and bottom) and restore them when tapping the screen. I thought this would be a standard function, but couldn't find how to do it.
As a reference, this is what Stanza or the NYT app do.
Set up a method that runs this on a tap event:
if (![navigationController isNavigationBarHidden])
[navigationController setNavigationBarHidden:YES animated:YES]; // hides
else
[navigationController setNavigationBarHidden:NO animated:YES]; // shows
As for the UIToolbar, it is a UIView subclass, so you should be able to pretty easily set up a custom animation for sliding this in and out of sight.
There is also quite a useful method for UIVIewController.
- (BOOL) hidesBottomBarWhenPushed {
//hide a toolbar or whatever
return NO;
}
Try this:
BOOL hide = ![self.navigationController isNavigationBarHidden];
[self.navigationController setNavigationBarHidden:hide animated:YES];
I guess recently you can use self.navigationController.hidesBarsOnTap = true;