Creating custom push segue - ios

I'm writing a custom segue class (HySegue) which allows views to animate the transition. The code is working great, except when under a UINavigationController stack. Actually, the transitions run and animate well, but the top UINavigationBar is what is causing me problems.
When first animating, I add the destination view as a subview of the source view. As such:
UIView * sourceView = sourceViewController.view;
UIView * destinationView = viewControllerToPresent.view;
// Force the source view to layout
[sourceView addSubview:destinationView];
[sourceView layoutIfNeeded];
When the transition is over, I present the destination view controller:
UIViewController * parentViewController = viewControllerToDismiss.parentViewController;
UIView * destinationView = destinationViewController.view;
// Break the view hierarchy that was setup earlier
[destinationView removeFromSuperview];
// When presenting in a UINavigationController stack, push the destination view controller
if ([parentViewController isKindOfClass:[UINavigationController class]]) {
[(UINavigationController *)parentViewController pushViewController:destinationViewController
animated:NO];
}
else {
// Present the destination view controller
[viewControllerToDismiss presentViewController:destinationViewController
animated:NO
completion:nil];
[viewControllerToDismiss willMoveToParentViewController:nil];
[viewControllerToDismiss.view removeFromSuperview];
[viewControllerToDismiss removeFromParentViewController];
[viewControllerToDismiss didMoveToParentViewController:nil];
}
The problem is that during the animation the destination view does not know that it's being pushed in a navigation stack and so the top bar, although visible, is not taken into account in the view's bounds. That is, the navigation bar is visible because it's visible for the source view controller, but the destination view controller knows nothing about it. When the animation finishes the destination view controller is pushed onto the stack, so it now knows about the navigation bar, and all my content with Top Space to Top Layout Guides constraints jumps down on the frame.
The top bar also doesn't show in IB. This is when I use my custom segue:
And this is when I use show segue:
Notice that the bar shows on the later but not on the former.
What I was wondering is how IB knows that it's a push segue. Is it some flag? Is it because of the specific class it's using? How would I make my custom segue also a push segue?
Edit: I loved the segue's type in prepareForSegue:sender: and it seems its type is UIStoryboardPushSegue, which is not a public or documented class. How can I can I solve it then? I already tried setting the destination view's frame and bounds from the source view.

Related

Manually Trigger `automaticallyAdjustsScrollViewInsets` at a Certain Time

I have a UINavigationController, containing a UIViewController that is parent to two UITableViewController controllers.
When the user taps on a segmented control in the UIToolbar of the navigation controller, the current child table controller is swapped out with the new one. This includes removing the old controller from the parent hierarchy and removing its view as a subview of the parent view controller.
The first view controller that is displayed when the navigation view controller first presents it has its contentInset correctly configured by automaticallyAdjustsScrollViewInsets, however, when I pull that one out and insert the view from the second table view controller, that does not.
Furthermore, if I rotate the device (Which shrinks the UINavigationBar) and then swap back to the first view controller, its contentInset is now incorrect and it doesn't scroll properly. The second controller, however, does have its contentInset property properly set as a result of the device rotation.
Is there a way to manually force a UIViewController to redo its automaticallyAdjustsScrollViewInsets operation when I need it?
It's not an absolutely amazing one, but I found a solution that works.
Inserting a new child view controller isn't enough to trigger UINavigationController to automatically work out the appropriate contentInset values for any scroll views in the new child. BUT! You can force it to perform that calculation by doing something that would have required it anyway. For example, hiding and showing the navigation bar or toolbar.
- (void)insertViewController:(UIViewController *)viewController
{
// Add the view to our view
viewController.view.frame = self.view.bounds;
[self.view addSubview:viewController.view];
// Add the new controller as a child
[self addChildViewController:viewController];
[viewController didMoveToParentViewController:self];
// Show and hide the toolbar to force the content inset calculation
self.navigationController.toolbarHidden = YES;
self.navigationController.toolbarHidden = NO;
}
I've tested it, and there appear to be no visual glitches by rapidly hiding either the navigation bar or toolbar, so this solution seems to be acceptable.

Use destinationViewController button in a custom segue

My goal is to make a custom segue with a custom animation as follows:
I want the segue to cover a button from the sourceViewController with a button from the destinationViewController with an effect similar to the navigation controller's push effect, i.e. the new button is supposed to push the old button away from right to left.
I have been able to make the old button (from the sourceViewController) move away as desired:
[UIView animateWithDuration:1.0 animations:^{
// set the target frame for animated view
sourceViewController.optionsButton.frame = leftButtonTargetFrame;
} completion:^(BOOL finished) {
[navigationController pushViewController:destinationViewController animated:NO];
// reset the button's frame back to its original frame
sourceViewController.optionsButton.frame = leftButtonInitFrame;
}];
But I am struggling to make the new button (from the destinationViewController) move in. The reason is that I cannot access the destinationViewController's view elements: While performing the segue they are not instantiated. And I cannot animate a button that is not instantiated.
So how can I replace a button in the sourceViewController with a button from the destinationViewController?
The view of the destination view controller hasn't been initialized/loaded at the time when you try to access the buttons. To load the view of the destination view controller, you can simply access the view property. Do this before using the buttons: [destinationViewController view];
destinationViewController.view; would also work, but it would generate a compiler warning.
Background Information:
If you access the view property and its value is currently nil, the view controller automatically calls the loadView method and returns the resulting view.
The method loadView loads the view that the controller manages. You should never call this method directly.
You are correct that you cannot animate an object that does not yet exist. However, you can fake it.
Create a place-holder button that will look identical to the button that will be in the new view controller.
Animate it to the correct place.
As the destination view controller comes in, its button should be invisible.
After the the view controller is in place (i.e. the segue has finished) the destination view controller can ensure the proper placement if its button and make its actual button visible.
Hope this helps.

Want to Push another View from current view

I am doing paypal integration and my project is working good.
But i want to push my Next view from my current view. first i used Navigation Controller but now i want to push it with out navigation controller.
I used the syntax with Navigation controller is
[self.navigationController pushViewController:[[[NextViewController alloc] initWithURL:[ECNetworkHandler sharedInstance].redirectURL returnURL:RETURN_URL cancelURL:CANCEL_URL] autorelease] animated:TRUE];
And i used the syntax to push another view controller without navigation controller is
NextViewController *webVcustome = [[NextViewController alloc]initWithURL:[ECNetworkHandler sharedInstance].redirectURL returnURL:RETURN_URL cancelURL:CANCEL_URL];
[self.view addSubview:webVcustome.view];
With Navigation it works but without navigation it don't.
What should i do to push the view controller.
instead of adding a subview call presentViewController:animated:completion, like this:
[self presentViewController:webVcustome animated:YES completion:nil];
for more information of this message take a look to the documentation
If you want to "push" a view without using UINavigationController , I think you can only use two views to adjust their frames when they are begin "push" movement.
eg:maybe you can creat 2 subviews such as : currentView , anotherView. And then add them to the self.view.
maybe you can set the currentViews frame is (0,0,320,480) and anotherViews frame is (320,0,320,480) , when you want to "push" them , you can set their frame is the currentViews frame is (-320,0,320,480) and anotherViews frame is (0,0,320,480) with a UIView animation

Source view controller hides during custom segue

I'm trying to make a custom segue so that the destination view controller slides down from the top.
I wrote my code according to the example from the documentation.
The problem is that when the segue is executed, the source view controller goes black, and then the animation occurs. How can I prevent the source view controller from going black?
(I already tried implementing the solution presented in this answer but the screen either goes black after the transition, or reverts to the source view controller.)
Here's my code:
-(void)perform{
UIViewController *splashScreen = self.sourceViewController;
UIViewController *mainScreen = self.destinationViewController;
//Place the destination VC above the visible area
mainScreen.view.center = CGPointMake(mainScreen.view.center.x,
mainScreen.view.center.y-600);
//Animation to move the VC down into the visible area
[UIView animateWithDuration:1
animations:^{
mainScreen.view.center = CGPointMake(mainScreen.view.center.x, [[UIScreen mainScreen] bounds].size.height/2 );
}
];
[splashScreen presentModalViewController:mainScreen animated:NO];
}
The reason that your source view controller seems to be hidden is that the destination view controller is presented right away.
When you are writing custom segues you don't have both views available at the same time. You could either
push view controller, add the source view to the destination view controller and animate
add the destination view to the source view controller and animate, then push view controller
push to an in-between view controller, add both views, animate, push to the destination view controller.
In all the above cases where I say push view controllers you could instead present view controllers modally. In fact that might be more suitable for the in-between view controller solution.

Display Modal View Controller over detail view in UISplitViewController

I have a UISplitViewController in an iPad app. When something is selected from the table I want to fade in a modal view controller over the detail view. I can present it without a problem, but for some reason I can't get it to match the frame of the detail view. I would like it to stick to the detail view controller frame on rotation as well. Does anyone have any experience with this? This is my code to display. The detail view controller reference is set in the app delegate and passed down the table controllers.
QuestionViewController_iPad *questionView = [[[QuestionViewController_iPad alloc] initWithNibName:#"QuestionViewController_iPad" bundle:nil] autorelease];
questionView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
// Not quite
questionView.modalPresentationStyle = UIModalPresentationCurrentContext;
questionView.questionQuizCon = [QuestionQuizConnection firstQuestionForQuiz:quizCatCon.quiz];
// Maybe something like this?
[self.detailViewController presentModalViewController:questionView animated:YES];
When the modal view presents, it matches the size of the detail view controller, but it doesn't but it sits on the top left of the screen behind the master view controller. It also doesn't resize on rotation. I have the springs and struts set to auto size and fill. The height changes on rotation but it won't fill the width.
I couldn't get this to look right any way I tried it so I ended up just using view transitions to make it look like pages being torn off a notebook. That looks better anyway.
// Transition the view on as a subview.
[UIView transitionWithView:self.detailViewController.pageView duration:1.0
options:UIViewAnimationOptionTransitionCurlUp
animations:^ {
questionView.view.frame = CGRectMake(0, 0, self.detailViewController.pageView.frame.size.width, self.detailViewController.pageView.frame.size.height);
[self.detailViewController.pageView addSubview:questionView.view];
// Watch this one
self.detailViewController.currentQuestionViewController = questionView;
}
completion:nil];
After [self.detailViewController presentModalViewController:questionView animated:YES]; you should set center property and/or frame of questionView. Be sure that you set it after presenting modal view.

Resources