Custom Transistion animation shows viewController with a blink - ios

I am working with a custom transition, animation like that of a push.
But when i use this code after my viewcontroller loaded after after animation it just blinks.
Here is the method i used to present my view controller
+(void)leftpresentFrom:(UIViewController *)fromviewcontroller
To:(UIViewController *)toviewcontroller
{
CGPoint newcenter = CGPointMake(480, toviewcontroller.view.center.y);
toviewcontroller.view.center =newcenter;
toviewcontroller.view.clipsToBounds=YES;
[fromviewcontroller.view addSubview:toviewcontroller.view];
[UIView animateWithDuration:.5
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
toviewcontroller.view.center = CGPointMake(160 ,toviewcontroller.view.center.y);
}
completion:^(BOOL finished){
[toviewcontroller.view removeFromSuperview];
[fromviewcontroller presentViewController:toviewcontroller animated:NO completion:^{
}];
}];
}

did you try removing the view after the new controller has been presented?
eg.
[fromviewcontroller presentViewController:toviewcontroller animated:NO completion:^{
[toviewcontroller.view removeFromSuperview];
}];

Related

Zoom segue from UICollectionView [duplicate]

I am trying to use a custom segue to perform a kind of zoom animation.
When the transition is executed, the sourceViewController goes black, then the zoom occurs.
Tried also to set the pushViewController: into the completion block but the transition is not executed at all.
- (void)perform {
UIViewController *sourceViewController = (UIViewController *) self.sourceViewController;
UIViewController *destinationViewController = (UIViewController *) self.destinationViewController;
[destinationViewController.view setTransform:CGAffineTransformMakeScale(0.5,0.5)];
[destinationViewController.view setAlpha:0.0];
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationCurveEaseOut
animations:^{
[destinationViewController.view setTransform:CGAffineTransformMakeScale(1.0,1.0)];
[destinationViewController.view setAlpha:1.0];
[sourceViewController.navigationController pushViewController:destinationViewController animated:NO];
}
completion:^(BOOL finished){
}];
}
What I am doing wrong ?
It feels kludgy, but you can try adding the destinationViewController.view as a subview before your animation and then when the animation is done, remove it and push it back on without animation. Solves the black screen before the transition, but perhaps not perfect, depending upon what you want to do with the navigation bar, but maybe closer:
[sourceViewController.view addSubview:destinationViewController.view];
[destinationViewController.view setFrame:sourceViewController.view.window.frame];
[destinationViewController.view setTransform:CGAffineTransformMakeScale(0.5,0.5)];
[destinationViewController.view setAlpha:1.0];
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationCurveEaseOut
animations:^{
[destinationViewController.view setTransform:CGAffineTransformMakeScale(1.0,1.0)];
[destinationViewController.view setAlpha:1.0];
}
completion:^(BOOL finished){
[destinationViewController.view removeFromSuperview];
[sourceViewController.navigationController pushViewController:destinationViewController animated:NO];
}];
Note, effective iOS 7, you would use custom transitions. For more information, see WWDC 2013 Custom Transitions Using View Controllers.
For example, if trying to do a custom transition with navigation controller, the first view controller would specify itself as the delegate of the navigation controller:
self.navigationController.delegate = self;
Then, it would specify the custom animators for push and pop, respectively:
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC
{
if (operation == UINavigationControllerOperationPush) {
return [[PushAnimator alloc] init];
} else {
return [[PopAnimator alloc] init];
}
}
And then you'd obviously implement these animators:
#interface PushAnimator : NSObject <UIViewControllerAnimatedTransitioning>
#end
#implementation PushAnimator
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
{
return 0.5;
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
[[transitionContext containerView] addSubview:toViewController.view];
toViewController.view.frame = fromViewController.view.frame;
toViewController.view.transform = CGAffineTransformMakeScale(0.5,0.5);
toViewController.view.alpha = 0.0;
[UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:0 animations:^{
toViewController.view.transform = CGAffineTransformIdentity;
toViewController.view.alpha = 1.0;
} completion:^(BOOL finished) {
[fromViewController.view removeFromSuperview];
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
#end
and
#interface PopAnimator : NSObject <UIViewControllerAnimatedTransitioning>
#end
#implementation PopAnimator
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
{
return 0.5;
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
[[transitionContext containerView] insertSubview:toViewController.view belowSubview:fromViewController.view];
toViewController.view.frame = fromViewController.view.frame;
[UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:0 animations:^{
fromViewController.view.transform = CGAffineTransformMakeScale(0.5,0.5);
fromViewController.view.alpha = 0.0;
} completion:^(BOOL finished) {
[fromViewController.view removeFromSuperview];
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
#end

UIView animateWithDuration ignores duration

My goal is simple and I have achieved this previously which is why I'm resorting to asking my question here.
I am trying to animate a subview. Simple enough. The view ends up exactly where I want it to be after the animation is over. The only problem is:
whatever I do the animation duration is completely ignored. It happens instantly.
- (void)callToDismissView:(UIView *)view {
[self.view addSubview:view];
[self dismissViewControllerAnimated:NO completion:nil];
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^(void){
CGRect frame = self.view.frame;
frame.origin.x = frame.size.width;
view.frame = frame;
} completion:^(BOOL finished){
[view removeFromSuperview];
}];
}
Now I have tried different frames and durations to see if the view was animated at all and it always ends up where I need it to be. Only instantly...
EDIT:
The above code is being called by a delegate in the dismissed view controller like so:
- (void)dismissSelf {
if (self.delegate && [self.delegate respondsToSelector:#selector(callToDismissScan)]) {
[self.delegate callToDismissScan];
}
}
And that method itself is triggered by a notification.
I must admit that some things are happening during the transition between the two controllers that I don't fully understand. (And I would very much like to understand them...)
You can try
[self.view layoutIfNeeded];
like this
- (void)callToDismissView:(UIView *)view {
[self.view addSubview:view];
[self dismissViewControllerAnimated:NO completion:nil];
[self.view layoutIfNeeded];
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^(void){
CGRect frame = self.view.frame;
frame.origin.x = frame.size.width;
view.frame = frame;
[self.view layoutIfNeeded];
} completion:^(BOOL finished){
[view removeFromSuperview];
}];
}
Maybe you need try like this.
- (void)callToDismissView:(UIView *)view {
[self.view addSubview:view];
CGRect frame = self.view.frame;
frame.origin.x = frame.size.width;
[UIView animateWithDuration:0.3 delay:0.3
options:UIViewAnimationOptionCurveEaseInOut animations:^(void){
view.frame = frame;
}
completion:^(BOOL finished){
[view removeFromSuperview];
//[self dismissViewControllerAnimated:NO completion:nil];//uncomment if need.
}];
}
It seems there was no way in hell I could animate the transition in the presenting view controller and so the simplest way to resolve the issue was to animate the transition in the presented view controller before it is being dismissed.
The way I did this was by casting the delegate to a view controller. It was then easy to add it's view as a sub-view of my presented view controller and animate it like so:
- (void)dismissSelf {
UIView *dummyView = [ScreenCapper captureScreenIn: self];
UIViewController *presentingViewController = (UIViewController *)self.delegate;
[self.view.window addSubview: presentingViewController.view];
[self.view.window addSubview: dummyView];
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^(void){
dummyView.frame = CGRectMake(dummyView.frame.size.width, dummyView.frame.origin.y, dummyView.frame.size.width, dummyView.frame.size.height);
} completion:^(BOOL finished){
if (self.delegate && [self.delegate respondsToSelector:#selector(callToDismissView)]) {
[self.delegate callToDismissView];
}
}];
}
And in the presenting view controller all that was left to do was to dismiss the presented view controller without animations.
- (void)callToDismissView {
[self dismissViewControllerAnimated:NO completion:nil];
}

Unbalanced calls for ViewController with own transition

I want to animate the transition of my LevelCompletedVC.
The LevelCompletedVC should come from Top to Bottom.
Here is my Code in the GameViewController:
LevelCompletedViewController *lcvc = [self.storyboard instantiateViewControllerWithIdentifier:#"levelCompletedViewController"];
[self.view addSubview:lcvc.view];
[lcvc.view setFrame:self.view.window.frame];
[lcvc.view setTransform:CGAffineTransformMakeTranslation(0, -self.view.frame.size.height)];
[lcvc.view setAlpha:1.0];
[UIView animateWithDuration:0.7 delay:0.0 options : UIViewAnimationOptionTransitionFlipFromTop
animations:^{
[lcvc.view setTransform : CGAffineTransformMakeTranslation(0, 0)];
[lcvc.view setAlpha:1.0];
}
completion:^(BOOL finished) {
[lcvc.view removeFromSuperview];
[self presentViewController:lcvc animated:NO completion:nil];
}];
If I want to present the second VC with:
LevelCompletedViewController *lcvc = [self.storyboard instantiateViewControllerWithIdentifier:#"levelCompletedViewController"];
[self presentViewController:lcvc animated:NO completion:nil];
theres no error.
But with my own transition i get:
Unbalanced calls to begin/end appearance transitions for LevelCompletedViewController.
Whats wrong?
I don't know when or where you present the second VC, but i got same
wrong before.
In my case, presentViewController are waiting other action done.
Try
dispatch_async(dispatch_get_main_queue(), ^(void){
LevelCompletedViewController *lcvc = [self.storyboard instantiateViewControllerWithIdentifier:#"levelCompletedViewController"];
[self presentViewController:lcvc animated:NO completion:nil];
});
hope this help you.

Swipe Gesture with Custom Segue

I am currently using a modal segue in my storyboard to go from one view to another with a button. And on the way back I am using a button to run a custom segue with my ABCustomSegue. It is all working fine I just want to be able to run this custom segue after the user preforms a swipe. How might I achieve that?
ABCustomSegue:
-(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.4
delay:0.0
options:UIViewAnimationOptionTransitionFlipFromBottom
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];
}];
}
Current Swipe Recognizer:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
UIScreenEdgePanGestureRecognizer *bezelSwipeGestureRecognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:#selector(swipeBack:)];
bezelSwipeGestureRecognizer.edges = UIRectEdgeTop;
bezelSwipeGestureRecognizer.delegate = self;
[self.view addGestureRecognizer:bezelSwipeGestureRecognizer];
UIView *invisibleScrollPreventer = [UIView new];
invisibleScrollPreventer.frame = CGRectMake(0, 0, self.view.frame.size.width, 30);
[self.view addSubview:invisibleScrollPreventer];
}
-(void)swipeBack:(UIScreenEdgePanGestureRecognizer *)recognizer
{
if (recognizer.state == UIGestureRecognizerStateEnded) {
NSLog(#"swipe back");
}
}
Thank you!
Try this code:
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];

Present modal controller from specified point

I have buttons on some viewController view. touchUpInside: methods present modal view controllers. I want to present them from center of tapped button frame. How can I achieve this result?
I tried:
webController.view.transform = CGAffineTransformScale(CGAffineTransformIdentity, self.buuton.center.x, self.button.center.y);
[self presentViewController:webController animated:NO completion:^{
// some code
}];
but it damaged my UI. I also tried to use [UIView beginAnimation], no success.
I have achieved something similar with a trick, adding destvc.view as subview to sourcevc.view, see below my functions to scale in and scale out.
You can use the same trick only as visual effect, and present your vc at the end, without animation:
+(void) animWithAlpha:(float)alpha view:(UIView*)view{
[UIView animateWithDuration:0.15
delay:0.0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
view.alpha = alpha;
}
completion:^(BOOL fin) {}];
}
+(void) zoomIN:(UIViewController*)sourceViewController destination:(UIViewController*)destinationViewController fromPoint:(CGPoint)point{
[sourceViewController.view addSubview:destinationViewController.view];
[destinationViewController.view setFrame:sourceViewController.view.window.frame];
[destinationViewController.view setTransform:CGAffineTransformMakeScale(0.15, 0.1)];
destinationViewController.view.center = point;
sourceViewController.view.userInteractionEnabled=NO;
destinationViewController.view.alpha = 0.5;
[self animWithAlpha:1 view:destinationViewController.view];
[UIView animateWithDuration:0.4
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
[destinationViewController.view setTransform:CGAffineTransformMakeScale(1, 1)];
destinationViewController.view.center = sourceViewController.view.center;
}
completion:^(BOOL finished){
if(finished){
[destinationViewController.view setTransform:CGAffineTransformMakeScale(1, 1)];
destinationViewController.view.center = sourceViewController.view.center;
sourceViewController.view.userInteractionEnabled=YES;
}
}];
}
+(void) zoomOUT:(UIViewController*)sourceViewController destination:(UIView*)destination toPoint:(CGPoint)point{
[sourceViewController.view setTransform:CGAffineTransformMakeScale(1.0, 1.0)];
[sourceViewController.parentViewController.view setUserInteractionEnabled:NO];
[destination setUserInteractionEnabled:NO];
[UIView animateWithDuration:0.4
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
[sourceViewController.view setTransform:CGAffineTransformMakeScale(0.01, 0.01)];
[sourceViewController.view setAlpha:1.0];
sourceViewController.view.center = point;
}
completion:^(BOOL finished){
if(finished){
[sourceViewController.view setTransform:CGAffineTransformMakeScale(1.0, 1.0)];
[sourceViewController.view removeFromSuperview];
sourceViewController.view.center = point;
[destination setUserInteractionEnabled:YES];
}
}
You have to do that through addSubview: method and doing something like:
- (void) appear: (UIView *) view fromPoint: (CGPoint) point
{
[view setBounds:self.view.bounds];
[view setCenter:point];
[view setAlpha:0.0];
[self addSubview:view];
[view setTransform:CGAffineTransformMakeScale(0, 0)];
[UIView animateWithDuration:0.3 animations:^{
[view setCenter:self.view.center];
[view setTransform:CGAffineTransformIdentity];
[view setAlpha:1.0];
}];
}
You have to create the view before call the method.
Good Luck!

Resources