UIPageViewController transitioning to another view on event - ios

I have a UIPageViewController with 3 views. I want to change from one view to another on a button event (something like snapchat buttons that help you through navigation, even though swipes also do the job). I'm currently using the following:
//the navWrapper is the view currently displayed
//it asks the PageViewController to set its view abruptly to the nextWrapper
[navWrapper.rootViewController.pageViewController setViewControllers:#[nextWrapper] direction:UIPageViewControllerNavigationDirectionReverse animated:NO completion:nil];
This works because it changes the view controller displayed correctly, but I'm looking a way to have that transition just like a swipe would look like (instead of the harsh change in the view with no animation that is going on right now).
Been looking around but haven't figured this out yet, suggestions are appreciated :)

Why not set animated to YES
[navWrapper.rootViewController.pageViewController setViewControllers:#[nextWrapper] direction:UIPageViewControllerNavigationDirectionReverse animated:YES completion:nil];
and if you are interested there is a way to trigger the gesture recognizer programmatically in this question

Related

After returning from using dismissViewControllerAnimated, clicking any other button crash app

I Have 2 views. View1 and view 2.
I am opening view 2 from view 1 by using
view2 *store2 = [[view2 alloc] initWithNibName:#"view2" bundle:[NSBundle mainBundle]];
[self presentViewController:store2 animated:YES completion:nil];
Then I have added a button on view2 to to dismiss view2 and return to view1 with the code:
[self dismissViewControllerAnimated:YES completion:nil];
The dismiss works well and get back to view1. But each time when I click on any button or any part on view1 after I return there, app crashes.
Kindly guide to go through this. I used this code in past projects and it always worked.
Sounds like no other object is retaining view1's view controller. The view is presented properly since it doesn't need to be retained by anybody in order to be displayed, however, once you try to interact with it, it need its view controller to be alive and responsive. My guess is that if you have view1's view controller as another object's property, or hold it in any other way as long as its view is displayed, you'll be able to use view1's buttons without crashing the app.

Visual artifact when dismissing more than one modal view controller at once

I've been struggling to find an answer to this question. I build a stack of modals via:
[[[NavA viewControllers] objectAtIndex:0] presentViewController:NavB animated:YES completion:NULL];
[[[NavB viewControllers] objectAtIndex:0] presentViewController:NavC animated:YES completion:NULL];
When I want to dismiss the NavA and NavB modals simultaneously I call
[[[NavA viewControllers] objectAtIndex:0] dismissViewControllerAnimated:YES completion:NULL];
This works fine except there's a brief flash where you can see NavB as the full stack is dismissed.
I stepped through the debugger and it looks like before the animation begins NavC disappears instantly and NavB dismisses with animation.
Is there any way to avoid this visual artifact and have the whole stack dismiss smoothly with NavC visible for the full duration of the animation?
Edit: To clarify, I'm presenting UINavigationController rather than UIViewController because this flow is for user login and has multiple possible branches that can lead back either to the current stage e.g. NavC (LoginPage), NavB (LandingPage with login and signup buttons) or all the way back to the root, NavA (main page of the application). In the iOS documentation they present a similar design pattern with the camera where each stage presents a UINavigationController with multiple possible view controllers https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ModalViewControllers/ModalViewControllers.html
Actually there's no way to do it by just using dismissViewControllerAnimated:completion: method no matter where you put it or how you call it (at least I couldn't, if someone knows a way - we all want to know).
HOWEVER, there's a hack you can use to achieve your desired outcome (this code should be called from "B" ViewController):
// Snapshot of "C" ViewController
UIGraphicsBeginImageContextWithOptions([UIScreen mainScreen].bounds.size, YES, 0);
UIView *snapshot = [self.presentedViewController.view snapshotViewAfterScreenUpdates:NO];
UIGraphicsEndImageContext();
// Cover the entire view of "B" (and hide navigation bar)
[self.view addSubview:snapshot];
self.navigationController.navigationBarHidden = YES;
// Dismiss "C" without animation
[self.presentedViewController dismissViewControllerAnimated:NO completion:^{
// Dismiss "B" with animation
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}];
If you are using a Storyboard then this should be achievable using Unwind Segues. Mike Woelmer has a good set of articles about this. Basically you provide information to the Storyboard about how a view can unwind through several different views to get a to a view that's already on the stack.
However, I'm a bit confused in the same way that Jeffery Thomas is in the comments: why are you presenting a navigation controller with another navigation controller? I can understand that you might want the navigation bar to look different on different views, but you can customise that when the view is due to appear. You should think a bit about the content of the views in NavB and NavC and ask yourself whether they are supposed to be presented as modal views or whether they would be better off as part of a single navigation stack. By presenting each Navigation Controller modally you're ending up with multiple navigation stacks, not a single stack with multiple view controllers. Even if just NavB and NavC were part of the same stack it would probably remove the visual glitch you're seeing.
If you did use a single navigation controller then you can get back to a previous view controller in the navigation stack by using the method -popToViewController:animated: on UINavigationController.
If you decide that presenting NavB and NavC modally as you are currently doing is the right thing to do then you are likely to get into trouble because when you ask NavA to dismiss its view controller it will try to dismiss NavB, which to it means setting up a transition between the NavB's view and NavA's view. That's why you're seeing that transition, and not the one you want (which is between NavC's view and NavA's). One way which might work (and sounds a bit weird) is to try to present NavA from NavC, then override the transition to make it look like you're popping NavC off the stack. Once you're there you can clean things up by removing any strong references to NavB and NavC. This article from Ash Furrow will get you most of the way.
You can fake the animation to look exactly as you wish:
pop/dismiss B and C without animation
push/present C without animation
pop/dismiss C using whatever animation you wish

iOS Showing views conditionally

I have a view in which a user selects an action to take and on that next screen there is a save and a back button. For both of the buttons the last line is dismissViewControllerAnimated:.
I need a way to make the 1st screen show only if the back button is used. save should send back to the main screen/rootViewController I am fairly new to iOS but not programming in general and just need a nudge in the right direction.
Could I set a bool flag to show or not? Maybe I can set the Tag on the view and then check that in the other screens on save/back? I assume I can check the parent view.
Sorry if this is a dup but I cant find anything specifically for this.
EDIT: I am not using a nav controller and am showing the views modally.
The answer will vary depending on how your UIViewControllers are structured and setup. If you're using a uinavigationcontroller then you can POP to the root view controller using:
[self.navigationController popViewControllerAnimated:YES];
If you're presenting your UIViewControllers modally, you can try to dismiss the presenting View Controllers of your modal view controller using the presentingViewController property:
[[[self presentingViewController] presentingViewController] dismissViewControllerAnimated:YES completion:nil];
You may also want to take a look at Unwind Segues if you're using a Storyboard:
What are Unwind segues for and how do you use them?
Finally, as far as determining whether the back button is pressed or another button - that depends on how the app is setup. You'll need to use your own logic (probably if / then statements or case / switch) to determine which button was pressed. You also may want to check out the sender argument in IBActions.
John, to have a UINavigationViewController return to it's root viewcontroller, you use:
[nameOfNavController popToRootViewControllerAnimated:YES];
The other guys are correct that the information you've provided is definitely not enough to determine exactly what you need to do.
You can use the presentingViewController property of a modal view controller to access it's presenting controller.
It turns out that I was using the terminology wrong. I am presenting all views modally and that is the issue, there is no navigation controller. I ended up using NSNotification to build a listener and had the main view controller listen and then dismiss the view and hence show itself. Worked a treat.
here is the link to the code I ended up with.
http://iphonedevsdk.com/discussion/114737/view-heirarchy-issues-possibly-from-the-camera
Hopefully this helps someone else.

presentViewController is disabling all removeFromSuperview messages in a UISplitViewController

Here is a visual representation of the UISplitViewController:
I'm trying to present a UIViewController (myVC) that's a subview of a UIView inside the DetailViewController of a UISplitViewController using this:
[appDelegate.splitViewController presentViewController:myVC animated:NO completion:nil];
It presents, I dismiss it, the app rotates without a hitch, then when I try to reload the detail view by clicking on a cell in the rootViewController (a UINavigationController), all the [orangeUIView removeFromSuperview] messages are mysteriously disabled (there are more orange UIViews hidden here that are inside a mainScrollView). The "INFO LABEL" in the topToolbar is updating, so I know the cell is sending data...
Why would this activity disable removeFromSuperview if presented using splitViewController? I've presented myVC using the detailViewController...
[appDelegate.detailViewController presentViewController:myVC animated:NO completion:nil];
which doesn't disable removeFromSuperview, but causes an assortment of other rotational crashes.
What's going on here?
Since this question was created as a result of a previous question, the answer to this problem was...try something else. I was unable to fix this problem by presenting a view controller, most likely because I'm using a custom UISplitViewController with a hierarchy I'd rather not get into.
Here is the solution I came up with:
Core Plot - Options on making the graph full screen - addSubview after presenting modal problems

iPad Partial Curl modal transition always curls to full screen

I'm using UIModalTransitionStylePartialCurl to show a modal view in iPad.
modalViewController.modalTransitionStyle = UIModalTransitionStylePartialCurl;
[[self parentViewController] presentModalViewController:modalViewController animated:YES];
self is the right side view controller of my SplitViewController.
When I do this, the page is curled all the way to the top even though the size of the view of modalViewController is small. I only need it to curl a little so it would reveal ONLY the area taken by modalViewController. What I'm trying to do is something exactly like the iPad maps application settings.
I tried using all the modalPresentationStyle options for the modal view and I also tried setting the modalPresentationStyle.view.frame to a small CGRect but still couldn't get it to work.
Can anybody help on this...thanks in advance..
Just leave a clean space (No Controls or Images) in the top of your PresentedViewController, the Framework make the rest.
I have yet to find a more optimal solution, but I've been able to get good results by making the modal (revealed) view the same size as the parent (curling) view. iOS looks at the subviews to determine where to stop the curling and shows "just enough" of the subview to keep the subview pieces on-screen.

Resources