Scenario:
I need to show 3 or more popups one after the other on button click in each popup. I have created a different viewcontroller and xib files for each popup. So for displaying each popup I have used presentViewController instead of pushViewController.
That is, I have used this:
[self presentPopupViewController:searchPopUpView animationType:0];
instead of
[self.navigationController pushViewController:searchPopUpView animated:YES];
For dismissing a popup, the following code has been written:
[self dismissPopupViewControllerWithanimationType:0];
Issue:
The popups are displaying perfectly, but the background gets darker and darker whenever a popup shows up. After all popups have been dismissed I have to finally click on the blank screen to remove those darker parts. How to overcome this issue?
I think you are using MJPopupViewController to show pop-up.
If it is so, Then try this.
Suppose there is a controllerA from which you want to show a pop-up controller popupControllerB.
Then in your controllerA add Notifications Observer
Code to write in controllerA :
// Add Notification Observer when your view initialise.
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(dismissPopup) name:#"DISMISS_POPUP" object:nil];
In viewWillDisappear remove the notifications observer
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
This method will be called when you Post-notification from your popupControllerB
-(void)dismissPopup {
[self dismissPopupViewControllerWithanimationType:MJPopupViewAnimationFade];
}
And In popupControllerB, Where you want to dismiss the Pop-up, write this code.
[[NSNotificationCenter defaultCenter] postNotificationName:#"DISMISS_POPUP" object:nil];
Above line of code will call a method written in your controllerA and dismiss the pop-up properly.
If you want to dismiss presented UIViewControllers you can use this code. I have used this approach to dismiss presentedViewControllers. It will dismiss all your presentedViewControllers on your rootViewController.
UIViewController* presVC = self.window.rootViewController;
while (presVC) {
UIViewController* temp = vc.presentingViewController;
if (!temp.presentedViewController) {
[vc dismissViewControllerAnimated:NO completion:^{}];
break;
}
vc = temp;
}
Related
I have an app that have a login view and then after the login is successes I want to have a view with a side menu.
I am using SWRevealViewController to make the slide menu.
But the problem as I said is the login view will be the first view not the SWRevealViewController.
I tried to do the following inside prepareForSegue method.
SWRevealViewController *revealViewController;
[revealViewController initWithRearViewController: [self.storyboard instantiateViewControllerWithIdentifier:#"MenuTableViewCell"]frontViewController:[self.storyboard instantiateViewControllerWithIdentifier:#"HomeViewController"]];
this is not working. That's the only code I have inside prepareForSegue method, I deleted the if statement because I only have one segue inside the loginview so I figured I don't need the IF.
Should I delete the SWRevealViewController from the storyboard? or make the segue from the login view to SWRevealViewController
I don't know what to do.
There's no explanation for situation for using SWRevealViewController inside the views not the first view.
I am building this app for iOS for objective c for iPhone.
Please help.
Thanks.
You should do your storyboard hierarchy like this.
Drag a ViewController and change a class to SWRevealViewController.
Drag a ViewController Embedded in NavigationController. Change class name to LoginViewController.
Change your NavigationController's storyboard ID to "LoginNavigationController".
Assign new custom segue named sw_front from SWRevealViewController to NavigationController and change class of segue to SWRevealViewControllerSegueSetController.
Drag a controller having TableView as a subView which is your MenuViewController for Sidebar.
Assign new custom segue named sw_rear from SWRevealViewController to MenuViewController and change class of segue to SWRevealViewControllerSegueSetController.
Now drag a ViewController named HomeViewController embedded in NavigationController and assign a custom segue with identifier "Home" and class with SWRevealViewControllerSeguePushController.
Change storyboard ID of NavigationController to "HomeNavigationController".
This should be the setup in your storyboard.
Now here is the coding part:
In SWRevealViewController.m
- (void)viewDidLoad{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(userSignedInSuccessfully) name:kUserSignedInNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(userSignOutSuccessfully) name:kUserSignedOutNotification object:nil];
// this flag should be maintained in user defaults
if(iSUserSignedIn){
//Show Home page if user is already signed in
[self showHomeScreen];
}
}
#pragma mark - Show Home screen
-(void)showHomeScreen
{
UINavigationController *navigation = [[UIStoryboard storyboardWithName:kStoryboardName bundle:nil] instantiateViewControllerWithIdentifier:#"HomeNavigationController"];
[self setFrontViewController:navigation];
[self setFrontViewPosition:FrontViewPositionLeft];
}
-(void)showLoginScreen{
UINavigationController *navigation = (UINavigationController *)[[UIStoryboard storyboardWithName:kStoryboardName bundle:nil] instantiateViewControllerWithIdentifier:#"LoginNavigationController"];
[self setFrontViewController:navigation];
[self setFrontViewPosition:FrontViewPositionLeft];
}
Now when user signed first save flag iSUserSignedIn in user defaults and post this notification.
//Post notification for successful sign in
[[NSNotificationCenter defaultCenter] postNotificationName:kUserSignedInNotification object:nil];
When user signed out set flag iSUserSignedIn to nil and post this notification.
//Post notification for successful sign out
[[NSNotificationCenter defaultCenter] postNotificationName:kUserSignedOutNotification object:nil];
I'm using the below notifications to reload ViewControllerA when my app comes back from background mode. It works correctly, but the applicationEnteredForeground: method gets called every time when I open the app again. For example if I close the app when ViewControllerB or ViewControllerC is on the screen and open it again the method will be called despite the viewDidLoad of ViewControllerB doesn't contain applicationEnteredForeground: method. I would like to know that how could solve this issue? My goal is to use applicationEnteredForeground: only when ViewControllerA was on the screen before I closed the app.
As a possible solution I would just remove the NSNotificationCenter in the viewDidDisappear, but since the observer is in the viewDidLoad it won't work when the user navigates back, because viewDidLoad won't be called again. Is there any fix for this?
- (void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(applicationEnteredForeground:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
}
- (void)applicationEnteredForeground:(NSNotification *)notification {
// do stuff...
}
You should remove ViewController A's event listener on viewWillDisappear and add it in viewWillAppear. That way, VC A will only be listening when it is the visible view controller.
You can check if a view controller is on screen by checking the window property of it's view. It will work in most standard cases.
- (void)applicationEnteredForeground:(NSNotification *)notification
{
if (self.view.window == nil) {
// Not on screen
return;
}
// do stuff...
}
I need to go back all the way to the view controller that presented the first navigation controller. However I haven't dismissed multiple controllers before at once, and when I've tried doing so, it doesn't work. It just goes to the first navigation controller instead of all the way to the one before it.
Here is my current code:
[(UINavigationController *)self.presentingViewController popViewControllerAnimated:NO];
[self dismissViewControllerAnimated:YES completion:nil];
I have a view controller which modally presents the first navigation controller. The first navigation controller screen is called Main View Controller. It then pushes to Login View Controller. Login View Controller does presentViewController to MenuViewController (UIViewController).
I need to get from MenuViewController all the way back to the view that presented the first navigation controller. Thanks.
Try this
UIViewController *vc = self;
while (vc.presentingViewController != nil) {
vc = vc.presentingViewController;
}
[vc dismissViewControllerAnimated:YES completion:nil];
One option would be to use NSNotifications.
You can add an observer in your first/root/initial UINavigationController subclass e.g.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(logout:)
name:#"LogoutNotification"
object:nil];
Then in your "logout:" method you have direct control over the initial UINavigationController rather than those further up the hierarchy.
You can then send an NSNotification from anywhere in the app in order to trigger the method.
e.g.
[[NSNotificationCenter defaultCenter] postNotificationName:#"LogoutNotification" object:self];
I'm new to iOS development so I feel like I'm missing some fundamental knowledge here.
I have view controller (VC) that displays some information that comes form the server. My VC has two notification center observers - one for successful response from server and one for error.
I added observers like this
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(getPlaceInfoFailed:)
name:kGetPlaceInfoRequestDidFailBlockNotification
object:nil];
In case of error I want to display alert and navigate to previous view controller. Let's name them view controllers A and B.
I'm using storyboards.
My problem is that when I return to A UI is completely messed up - navigation bar has random stuff, my table view has garbage and etc. Eventually app crashes.
Here is how I tried to dismiss my VC B
- (void)getPlaceInfoFailed:(NSNotification *)notification {
dispatch_async(dispatch_get_main_queue(), ^{
//[self.navigationController popViewControllerAnimated:YES];
//[self dismissViewControllerAnimated: YES completion: nil];
//[self.presentingViewController dismissViewControllerAnimated: YES completion: nil];
//[self.presentedViewController dismissViewControllerAnimated: YES completion: nil];
//[self performSegueWithIdentifier:#"exitSegue" sender:self];
});
}
Version [self performSegueWithIdentifier:#"exitSegue" sender:self]; works when I invoke it, for example, in button action handler.
But not in observer :( As you can see I tried to invoke performSegue in UI thread - no difference.
What am I doing wrong ?
Thank you!!!
What I would suggest is just dismiss the VC when the notification fires and handle the UI mishap in viewWillAppear of your parent controller/presenting controller - VC A.
This code should be in B if I am not wrong
- (void)getPlaceInfoFailed:(NSNotification *)notification {
[self dismissViewControllerAnimated: YES]; or try
[self dismissModalViewControllerAnimated:YES]; //dep'd in ios 6.
}
Looks like my problem was that I was calling performSegueWithIdentifier before viewDidAppear and that why it didn't work.
How I can handle two asynchronous events - view creation and requesting server I don't know yet.
I'm displaying a popover in iPad with a UINavigation bar. On the second view, I have a UISearchController that can display a keyboard. The keyboard pushes the popover up, which is fine, however if I now push the 'back' button on the UINavigation bar it dismisses the keyboard which is fine, but the popover doesn't slide back down to its original position. Anyone know how to fix that? Thanks!
Ok so I actually figured out (I believe) what your question was asking...and just in case anyone stumbles upon this from google, I figured I'd answer how I did it. It feels like a hack job but I haven't been able to find any other way to do it.
In the controller that brings up the keyboard,I had it post a notification whenever the keyboard dismisses:
[aTextField resignFirstResponder];
[[NSNotificationCenter defaultCenter] postNotificationName:#"movePopups" object:nil];
Then back on my home screen controller, that controls the UIPopover, I added a listener:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(movePopUpToRightLocation)
name:#"movePopups"
object:nil];
inside the init. Be sure to remember to remove the listener in your dealloc for good programming practice:
[[NSNotificationCenter defaultCenter] removeObserver:self];
So then whenever I get notification that the keyboard disappears, I get a reference to the button that the popover shows up from, and just have it re-appear directly from it:
-(void)movePopUpToRightLocation {
NSLog(#"move pop up to right location");
if (morePopUp) {
UIBarButtonItem *barButtonItem = (UIBarButtonItem *)[[bottomToolBar items] objectAtIndex:0];
[morePopUp presentPopoverFromBarButtonItem:barButtonItem
permittedArrowDirections:UIPopoverArrowDirectionDown
animated:YES];
}
}
I haven't added any checks for which popup it is, but I can easily do that if I have more than 1 type of popover / button that it would appear from. But that's the basic premise that you can go from.
Hope it helps!
You could also register for the UIKeyboardDidHideNotification somewhere in the initializer.
[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(movePopoverBack:) name:UIKeyboardDidHideNotification object:nil];
This code moves the popover back:
- (void)movePopoverBack:(id)sender {
if ([self.settingsPopoverController isPopoverVisible]) {
[self performSelector:#selector(hidePopover) withObject:nil afterDelay:0.1];
[self performSelector:#selector(movePopoverBack) withObject:nil afterDelay:0.5];
}
}
- (void)hidePopover {
[self.settingsPopoverController dismissPopoverAnimated:YES];
}
- (void)movePopoverBack {
[self.settingsPopoverController
presentPopoverFromBarButtonItem:self.bottomToolbar.settingsButton
permittedArrowDirections:UIPopoverArrowDirectionDown
animated:YES];
}
I didn't get it working without the delays, but this seems to be acceptable for my current project. Hope it helps someone.
After you press the Back button you should manually call resignFirstResponder for the search field (for example inside viewDidDisappear).
This should help, but the issue still will be reproduced under iOS 4 when the device is in Landscape orientation with Hthe ome button on the left side