Can I set maximum alpha for CATransition? - ios

Is it possible to adjust the maximum alpha (opacity) in a CATransition for when the views fade in and out?
What I want is something that looks like a modal segue. Compared to a default modal segue, the transition given by CATransition is very «dramatic».
Say I have two views.
A: the view I want to transition from.
B: the view I want to transition to.
I want B to come moving in from the bottom over A. For this I use the kCATransitionMoveIn type, with subtype kCATransitionFromTop (which is weird because B is moving up from bottom, not top).
In the default modal segue, this works fine, and A is only greyed out a little. With CATransition, A is totally black at towards the end of the transition when B has moved about 70% over A.
Code:
UIStoryboard *loginBoard = [UIStoryboard storyboardWithName:#"Login" bundle:nil];
UIViewController *vc = [loginBoard instantiateInitialViewController];
UIWindow *keyWindow = [[[UIApplication sharedApplication] delegate] window];
[keyWindow insertSubview:vc.view belowSubview:keyWindow.rootViewController.view];
CATransition *transition = [CATransition animation];
transition.duration = 0.5;
transition.type = kCATransitionMoveIn;
transition.subtype = kCATransitionFromTop;
[keyWindow.layer addAnimation:transition forKey:kCATransition];
[keyWindow.rootViewController.view removeFromSuperview];
keyWindow.rootViewController = vc;
The problem originates from here.

After digging around some more I figured that you simply can't set a maximum opacity / alpha for the CATransition that you get out of the box.
So I solved it like this:
//offset the frame
vc.view.frame = CGRectMake(0, CGRectGetHeight(self.view.bounds), CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds));
[UIView animateWithDuration:5
animations:^{
//insert over/before root view instead of after
[keyWindow insertSubview:vc.view aboveSubview:keyWindow.rootViewController.view];
vc.view.frame = CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds));
keyWindow.rootViewController.view.alpha = 0.8;
}
completion:^(BOOL finished) {
NSLog(#"completed! now you can change the rootviewcontroller etc..");
}];

Related

Using CATransition to custom viewcontroller transition animation

I have two viewcontroller A and B. A support portrait and landscape, B only support portrait.The below codes are on A.
UIStoryboard *board = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
B *vcb = [board instantiateViewControllerWithIdentifier:#"B"];
CATransition *a=[CATransition animation];
a.duration = 0.4f;
a.type = kCATransitionMoveIn;
a.subtype = kCATransitionFromTop;
a.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
[self.view.window.layer addAnimation:a forKey:#"kTransitionAnimation"];
[self presentViewController:vcb animated:NO completion:nil];
And on B ,i do the dissmiss.
CATransition *a=[CATransition animation];
a.duration = 0.4f;
a.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
a.type = kCATransitionReveal;
a.subtype = kCATransitionFromBottom;
[self.view.window.layer addAnimation:a forKey:#"dismiss"];
[self dismissViewControllerAnimated:NO completion:nil];
It works ok on portrait mode. But it works wrong when i do the bellow steps:
1. Present the B on portrait mode
2. Turn the cellphone to landscape and then click to dissmiss B.
3. The animation was wrong.
Can anybody explain this and how to fix it.I want the B act same as on the portrait mode.
Not sure, I understand your question correctly. Probably you should handle the DeviceOrientation in your Controller A.

Sliding a view controller from bottom with a Gesture

I have a question (Objective-C related).
I want to create a sliding from bottom ViewController on top of the Root Map View Controller by a click on the annotation.
1) After a click on the annotation it should slide from bottom and show 10% of the height;
2) after an upward swipe gesture - it should show up to 100% if the user drags it upwards fully;
3) on the downward gesture user should be able to decrease its visible height to 10% again;
4) on the MapView click the bottom ViewController should hide.
I'm including the Visual scheme of the process implementation.
Any ideas are very very appreciated!
check this demo
NHSlidingController
PanningViewController
You can always try to write your own segue animation to transition between ViewControllers. Just make a custom UIStoryboardSegue, and override its perform method. Here is a snippet to start with:
#interface HorizontalSegue : UIStoryboardSegue
#property CGPoint originatingPoint;
#end
#implementation VerticalSegue
- (void)perform {
UIViewController *sourceViewController = self.sourceViewController;
UIViewController *destinationViewController = self.destinationViewController;
NSArray* windowArray = [UIApplication sharedApplication].windows;
if (windowArray.count > 0) {
UIWindow* appWindow = [windowArray lastObject];
[appWindow insertSubview:destinationViewController.view aboveSubview:sourceViewController.view];
}
else
[sourceViewController.view addSubview:destinationViewController.view];
// Store original centre point of the destination view
CGPoint originalCenter = destinationViewController.view.center;
// Set center to start point of the button
destinationViewController.view.center = CGPointMake(self.originatingPoint.x, self.originatingPoint.y*3);
[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
}];
}
#end
Using this you can easily make custom animations. I am not totally sure if the part with adding the ViewController to the window is correct, but this is something that you could try and check/correct yourself.
Another way of animating segues is using CATransition:
-(void)perform
{
UIViewController *sourceViewController = (UIViewController*)[self sourceViewController];
UIViewController *destinationController = (UIViewController*)[self destinationViewController];
CATransition* transition = [CATransition animation];
transition.duration = 0.25;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionMoveIn; //kCATransitionMoveIn; //, kCATransitionPush, kCATransitionReveal, kCATransitionFade
transition.subtype = kCATransitionFromLeft; //kCATransitionFromLeft, kCATransitionFromRight, kCATransitionFromTop, kCATransitionFromBottom
[destinationController.view.layer addAnimation:transition forKey:kCATransition];
[sourceViewController presentViewController:destinationController animated:NO completion:nil];
}

how to make the modal view controller transparent

I am using present view controller for displaying a new view controller from left..
the code i used is..
UIViewController *controller;
UINavigationController *navi;
UIView *popmenu = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 300)];
popmenu.backgroundColor = [UIColor yellowColor];
controller.view = popmenu;
controller.view.superview.backgroundColor = [UIColor clearColor];
navi = [[UINavigationController alloc]initWithRootViewController:controller];
navi.view.superview.backgroundColor = [UIColor clearColor];
CATransition *transition = [CATransition animation];
transition.duration = 0.4;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromLeft;
[self.view.window.layer addAnimation:transition forKey:nil];
[self presentViewController:navi animated:NO completion:nil];
navi.view.superview.frame = CGRectMake(0, 0, 200, 540);
the output i got is..
here i can resize the view of the view controller, but how to resize the view controller so that the view present in background i mean the view from which this modal view is called will be visible and i can do operations..like having a button to close this modal view.. thank you..
You can make the presented view controller transparent but the presenting view controller will always disappear (i.e. the background becomes black) if you use the presentViewController:animated:completion: method without specifying a UIViewControllerTransitioningDelegate for the presented controller.
Here's a good tutorial that explains how to make custom transitions on iOS 7
http://www.doubleencore.com/2013/09/ios-7-custom-transitions/
And here's my experiment of it:
https://github.com/Jafared/CustomTransitionTests
Note that it'll work only on iOS 7
I am using this solution.. instead of creating another controller and other stuff..this seem pretty easy.
[UIView animateWithDuration:1.0 animations:^{
//Move frame or transform view
popmenu.frame = CGRectMake(0,0,200,570);
table.frame = CGRectMake(200, 0, 120, 570);
}];
I used the following approach on iOS7.
It adds the view above the navigation-controller, in the correct orientation, responds to orientation-changes of the new and underlying view-controller and the background is finally transparent.
UIView *rootView = [[[[self view] window] rootViewController] view];
UIView *myView = [[self myViewController] view];
[myView setFrame:[rootView bounds]];
[myView setTranslatesAutoresizingMaskIntoConstraints:YES];
[myView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
[rootView addSubview:myView];
This means you have to implement your own animation though.

iOS 7 present modal view inside UINavigationController?

My app is setup using a UINavigationController for all of the navigation. I am wanting to use a modal transition to present a specific view controller in the app. The thing is that I want to keep that new VC embedded inside of the navigation controller, but just that one view needs to use a modal animation rather than push.
How can I go about implementing this modal animation/transition on a single view controller within the UINavigationController?
Keep in mind that after this modal animation happens there will be buttons on that page that will proceed to work in line with a standard UINavigationController push animation.
ITviewViewController *vc = [[UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:#"vc"];
vc.modalPresentationStyle = UIModalPresentationFullScreen;
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:vc animated:YES completion:Nil];
Replace the pseudo code with your view controller names.
With iOS7, this is possible using the new custom transitioning API. You can find more information here: http://www.objc.io/issue-5/view-controller-transitions.html
You create an animation controller (interactive or otherwise), and pass it in the appropriate method of the navigation bar delegate. In your animation controller, you perform the custom animation using UIView animation API. In your case, the animation should perform a slide from bottom into place for forward animation, and slide from place to bottom for reverse animation. If you support interactive animation, you can even control the curve of the animation in relation to the finger slide.
Modal view by default is full screen. You need to change presentation style to show navigationBar
EDIT : This only works for iPad. For iPhone you can use MZformsheet or Kentnguyen to get semi modal behavior
MyModalViewController *targetController = [[[MyModalViewController alloc] init] autorelease];
targetController.modalPresentationStyle = UIModalPresentationFormSheet;
targetController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal; //transition shouldn't matter
[self presentModalViewController:targetController animated:YES];
targetController.view.superview.frame = CGRectMake(0,44/*navigation bar's height*/,height, width);//it's important to do this after
// use full screen height and width here
targetController.view.superview.center = self.view.center;
Use this line not presentModelViewController
[self presentViewController:vc animated:YES completion:Nil];
Maybe something like this will work for you (self is UINavigationController):
- (void)verticalPushViewController:(UIViewController *)controller
{
[UIApplication sharedApplication].keyWindow.backgroundColor = [UIColor colorWithWhite:1 alpha:0.9];
CATransition* transition = [CATransition animation];
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
transition.duration = 0.3;
transition.type = kCATransitionMoveIn;
transition.subtype = kCATransitionFromTop;
[self.view.layer addAnimation:transition forKey:kCATransition];
[self pushViewController:controller animated:NO];
}
- (UIViewController *)verticalPopViewController
{
[UIApplication sharedApplication].keyWindow.backgroundColor = [UIColor colorWithWhite:1 alpha:0.9];
CATransition* transition = [CATransition animation];
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
transition.duration = 0.3;
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromBottom;
[self.view.layer addAnimation:transition forKey:kCATransition];
return [self popViewControllerAnimated:NO];
}
The simplest way.
To present
LaunchImageViewController *launchView = [self.storyboard instantiateViewControllerWithIdentifier:#"launchImage"];
[[UIApplication sharedApplication].keyWindow addSubview:launchView.view];
To close. I calling this inside presented(LaunchImageViewController).
[self.view removeFromSuperview];

Present ViewController with custom animation

I am presenting a view controller using the foll. code:
VC_B * b = [[VC_B alloc] init...];
[self presentViewController:b animated:YES completion:nil];
I am trying to animate appearance of the view controller: the incoming VC should slide down from top covering VC that is currently displayed. following this solution makes it work with one problem: current VC disappears before the incoming VC appears on the screen. Is there a way to resolve this? perhaps there is an alternative solution to achieve this effect.
Try this code :
CreateNewViewController *newViewController = [[CreateNewViewController alloc]initWithNibName:#"CreateNewViewController" bundle:nil];
CATransition *transition = [CATransition animation];
transition.duration = 0.05;
transition.timingFunction = [CAMediaTimingFunction
functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type =kCATransitionMoveIn;
transition.subtype =kCATransitionFromTop;
transition.delegate = self;
[self presentModalViewController:newViewController animated:NO];
[self.view insertSubview:newViewController.view atIndex:0];
[self.view.layer addAnimation:transition forKey:nil];
Hope this will help you .
Try the below code. You just need to call below method from the point where you want to display NewViewController. What you need to do is that you just need to change the OriginY of NewViewcOntroller's View Frame.
-(void)displayNewVC
{
YourNewViewController *newVC = [[YourNewViewController alloc] init];
CGFloat originY = -450;//set originY as you want to display newViewController from the Top to bottom with animation
//initially set originY out of the Frame of CurrentViewcontroller
newVC.view.frame = CGRectMake(orginX, originY, newVC.view.frame.size.width, newVC.view.frame.size.height);
/*Display View With Animation*/
originY = 300;
[UIView animateWithDuration:.3 animations:^{
//set new originY as you want.
newVC.view.frame = CGRectMake(orginX, originY, newVC.view.frame.size.width, newVC.view.frame.size.height);
} completion:NULL];
[currentViewController.view addSubview:newVC.view];
}

Resources