hi i'm trying to create a custom modal segue that slides the src view controller to right which reveals destination view controller behind it. any ideas on how i can acheive it
so far i have tried this but it's not working.
#import "CustomMenuSegue.h"
#implementation CustomMenuSegue
- (void) perform {
UIViewController *src = (UIViewController *) self.sourceViewController;
UIViewController *dst = (UIViewController *) self.destinationViewController;
[UIView transitionWithView:src.navigationController.view duration:0.2 options:UIUserInterfaceLayoutDirectionRightToLeft
animations:^{
[src.navigationController modalTransitionStyle:dst animated:YES];
}
completion:NULL];
}
#end
Related
I have written a custom segue, because i wanted to add my own animations to it. Everything works alright, besides the fact that the viewDidLoad method in the target view CiewController gets called twice. Here is the perform method for my segue:
- (void)perform
{
UIViewController* sourceViewController = self.sourceViewController;
UIViewController* destinationViewController = self.destinationViewController;
[sourceViewController.view addSubview:destinationViewController.view];
CGPoint originalCenter = destinationViewController.view.center;
destinationViewController.view.center = CGPointMake(self.originatingPoint.x * 3, self.originatingPoint.y);
[UIView animateWithDuration:0.25
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
destinationViewController.view.center = originalCenter;
}
completion:^(BOOL finished) {
[sourceViewController presentViewController:destinationViewController animated:NO completion:NULL]; // present VC
}];
}
Does anyone have any idea what could cause this?
[----- EDIT -----]
The segue is present in the storyboard as a custom segue with a segue class that I have written myself. The only thing that is different in my class is the perform method which I have put above. The segue is called through a button, and the prepareForSegue method is called only once.
[----- EDIT 2 -----]
I checked the viewDidLoad method of the targetVC and it is only called once per segue. Nonentheless, it would be much more convenient for me to use viewWillAppear, so do you maybe know a different way in which i can do this animation?
I suggest you to use UIViewControllerTransitioningDelegate and UIViewControllerAnimatedTransitioning which are the more appropriate conventions to use for transitions since iOS 7.0. Since iOS 8.0 you also gain UIPresentationController support which allows you to build even richer transitions.
Example:
#interface ModalTransitionAnimator : NSObject<UIViewControllerAnimatedTransitioning>
#property (nonatomic) CGPoint originatingPoint;
#end
#implementation ModalTransitionAnimator
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
return 0.25;
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
NSTimeInterval duration = [self transitionDuration:transitionContext];
UIView* sourceView = [transitionContext viewForKey:UITransitionContextFromViewKey];
UIView* destinationView = [transitionContext viewForKey:UITransitionContextToViewKey];
UIView* container = transitionContext.containerView;
[container addSubview:destinationView];
CGPoint originalCenter = destinationView.center;
destinationView.center = CGPointMake(self.originatingPoint.x * 3, self.originatingPoint.y);
[UIView animateWithDuration:duration animations:^{
destinationView.center = originalCenter;
}
completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
}
#end
Then in prepareForSegue you simply assign transitioning delegate and implement UIViewControllerTransitioningDelegate to return appropriate animators for presentation or dismissal.
#interface ViewController : UIViewController<UIViewControllerTransitioningDelegate>
#end
#implementation ViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
UIViewController* controller = (UIViewController*)segue.destinationViewController;
controller.transitioningDelegate = self;
controller.modalPresentationStyle = UIModalPresentationCustom;
controller.modalPresentationCapturesStatusBarAppearance = YES;
}
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
ModalTransitionAnimator *animator = [[ModalTransitionAnimator alloc] init];
animator.originatingPoint = /* ... */;
return animator;
}
#end
Since this is a modal transition, you have to use presentViewController:animated: when presenting controllers with it. Therefore use normal "show" segues in Storyboards and they will automatically run all animations under the hood, no need to reinvent segues here.
I had example of how to build custom transitions somewhere on Github:
https://github.com/pronebird/CustomModalTransition/tree/ios8
When I am creating a custom segue from one view controller to another, there's a problem with showing top bar properly.
This is the code for custom segue:
#implementation CustomSegue
- (void)perform {
UIViewController *sourceViewController = self.sourceViewController;
UIViewController *destinationViewController = self.destinationViewController;
[sourceViewController.view addSubview:destinationViewController.view];
destinationViewController.view.alpha = 0.0;
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
destinationViewController.view.alpha = 1.0;
}
completion:^(BOOL finished){
[sourceViewController presentViewController:destinationViewController animated:NO completion:NULL];
[destinationViewController.view removeFromSuperview];
}];
}
#end
I am using storyboard to set this up and sourceViewCotoller is embeded in NavigationViewController.
After performing a segue, there is no top bar in th destinationViewController.
I found an answer that I should add a Navigation Item to the destinationViewController - doesn't help.
Another way of dealing with this that I found is embedding the destinationViewController in NavigationViewController.
After doing this, the top bar is visible, but also during the segue.
It's probably because I am adding the desitnationViewController into sourceViewController, so at the beginning of segue I have 2 top bars visible one below another.
How to deal with this ?
I am trying to implement a flip between two view controllers embedded into a container view. In the real app, the flip button swaps between a map and a list.
In this mockup of the problem, the Coffee UITableViewController is swapped out for the Sweets UIViewController.
It works fine in the simple case, but when I add a segue to the Sweets Controller to go to a child UIViewController, things go awry after the following actions - Flip - segue - Back - Flip. Repeat those actions and the tableview slowly makes its way down off the screen.
The code in FlipViewController is:
#interface FlipViewController ()
#property (strong, nonatomic) UIViewController *controller1;
#property (strong, nonatomic) UIViewController *controller2;
#property (strong, nonatomic) UIViewController *currentViewController;
#end
#implementation FlipViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.controller1 = [self.childViewControllers firstObject];
self.currentViewController = self.controller1;
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Storyboard" bundle:nil];
self.controller2 = [storyboard instantiateViewControllerWithIdentifier:#"Sweets Controller"];
[self addChildViewController:self.controller2];
}
- (IBAction)flip:(id)sender {
if (self.currentViewController == self.controller1) {
[self transitionFromViewController:self.controller1 toViewController:self.controller2 duration:0.3 options:UIViewAnimationOptionTransitionFlipFromRight animations:nil completion:^(BOOL finished) {
[self.controller2 didMoveToParentViewController:self];
self.currentViewController = self.controller2;
}];
}
else {
[self transitionFromViewController:self.controller2 toViewController:self.controller1 duration:0.3 options:UIViewAnimationOptionTransitionFlipFromRight animations:nil completion:^(BOOL finished) {
[self.controller2 didMoveToParentViewController:self];
self.currentViewController = self.controller1;
}];
}
}
#end
Some debugging seems to indicate the bounds of the UITableView is getting confused upon return. Do I have an AutoLayout problem or is my approach with transitionFromViewController: the wrong way to go about getting this effect? Any suggestions would be appreciated, I've been stuck on this bug for too long!?
I am trying to use a custom transition. I want a "cover vertical" transition from View Controller 1 to 2 and then have View Controller 2 (the middle one) slide back down again when moving to View Controller 3. Storyboard shown below:
http://i.stack.imgur.com/bJYXI.png
Im using the tutorial that is linked to from this post. And have also replaced the .m code with the code provided in the answer:
Xcode custom segue - Opposite of Cover Vertical (top to bottom) - COMPLETE NEWBIE
I have created a subclass of UIViewController and named it FromTopReplaceSegue. My .h and .m code is shown below:
.h
#import <UIKit/UIKit.h>
#interface FromTopReplaceSegue : UIViewController
#property(nonatomic, readonly) id sourceViewController;
#property(nonatomic, readonly) id destinationViewController;
#end
.m
#import "FromTopReplaceSegue.h"
#interface FromTopReplaceSegue ()
#end
#implementation FromTopReplaceSegue
-(void)perform{
UIViewController *sourceViewController = (UIViewController *) self.sourceViewController;
UIViewController *destinationViewController = (UIViewController *) self.destinationViewController;
[sourceViewController.view addSubview:destinationViewController.view];
[destinationViewController.view setFrame:sourceViewController.view.window.frame];
[destinationViewController.view setTransform:CGAffineTransformMakeTranslation(0, -sourceViewController.view.frame.size.height)];
[destinationViewController.view setAlpha:1.0];
[UIView animateWithDuration:0.75
delay:0.0
options:UIViewAnimationOptionTransitionFlipFromTop
animations:^{
[destinationViewController.view setTransform:CGAffineTransformMakeTranslation(0, 0)];
[destinationViewController.view setAlpha:1.0];
}
completion:^(BOOL finished){
[destinationViewController.view removeFromSuperview];
[sourceViewController presentViewController:destinationViewController animated:NO completion:nil];
}];}
#end
When i try to run the simulator i can easily get from Controller View 1 to 2 but it crashes when i try to move from Controller view 2 to 3 using the custom segue.
Can anyone help.
Thank you so much in advance! Struggling here! :)
Some time gone since my iOS days, but shouldn't the .h not define a subclass of a seque class instead of a viewcontroller? Like
#interface FromTopReplaceSegue : UIStoryboardSegue
You can read its documentation for some notes on subclassing as well...
I am doing an iPad app with UISplitViewController. I want to open a modalViewController in the masterViewController itself. When I load my view controller modally, it takes a whole screen to present it.
Here it is my code, which is in my masterViewController.m to present the new viewController modally
- (void)addNewContactButtonPressed:(id)sender {
AddOrEditContact *addContact = [self.storyboard instantiateViewControllerWithIdentifier:#"AddOrEditContact"];
addContact.screenMode = addMode;
UINavigationController *navigationController = [[UINavigationController alloc]initWithRootViewController:addContact];
[self.navigationController presentViewController:navigationController animated:YES completion:nil];
}
I want to load a new viewController modally inside the masterViewController. Any help would be appreciated.
You can't present a modal viewController over the masterViewController only, but you can add a childView controller to the masterViewController nd perform your own animation to present it
- (void)addiewControllerToHierarchy:(UIViewController *)viewController
{
[self addChildViewController:viewController];
[self.view addSubview:frontViewController.view];
if ([viewController respondsToSelector:#selector(didMoveToParentViewController:)])
{
[viewController didMoveToParentViewController:self];
}
}
and to remove
- (void)_removeViewControllerFromHierarchy:(UIViewController *)viewController
{
[viewController.view removeFromSuperview];
if ([viewController respondsToSelector:#selector(removeFromParentViewController)])
{
[viewController removeFromParentViewController];
}
}
this example doesn't have animation and probably you need to adjust the frame of the view etc... but I hope could help you