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];
}
Related
Im trying to fade in and out of a light node I have created I just dont know where to call the function accordingly so it will continously fade in and out. Never tried animating anything here is what I have.
- (void)fadeOutIn:(UIView *)view duration:(NSTimeInterval)duration
{
[self enumerateChildNodesWithName:#"//*" usingBlock:^(SKNode *node, BOOL *stop) {
if ([node.name isEqualToString:#"light1"]) {
[UIView animateKeyframesWithDuration:5 delay:2 options:UIViewAnimationOptionRepeat|UIViewAnimationOptionAutoreverse|UIViewAnimationCurveEaseInOut animations:^{
node.alpha = 0;
} completion:^(BOOL finished) {
}];
}
}];
}
where should I call this function?that is fades in and out continously?
Should it be called within an action?
Thank You
Use this for Continue fade in out.
-(void)viewDidAppear:(BOOL)animated{
[UIView animateKeyframesWithDuration:1 delay:0 options:UIViewAnimationOptionRepeat|UIViewAnimationOptionAutoreverse|UIViewAnimationCurveEaseInOut|UIViewAnimationOptionAllowUserInteraction animations:^{
node.alpha = 0;
} completion:^(BOOL finished) {
[UIView animateWithDuration:1 animations:^{
node.alpha = 1;
} completion:nil];
}];
}
-(void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[objAnimate setAlpha:1.0];
[UIView animateKeyframesWithDuration:2.0 delay:0.0 options:UIViewKeyframeAnimationOptionCalculationModeLinear | UIViewAnimationOptionCurveEaseInOut|UIViewAnimationOptionRepeat|UIViewAnimationOptionAutoreverse animations:^{
[objAnimate setAlpha:0.0];
} completion:nil];
}
This will create continuous fade in and out for your object when it appears. If you want to create programmatically a custom object and then use this code then do it after your custom object is added in your view as below (example):
objAnimate = [[UILabel alloc] initWithFrame:CGRectMake(20, 50, 200, 40)];
objAnimate.backgroundColor = [UIColor lightGrayColor];
[objAnimate setAlpha:1.0];
[self.view addSubview:objAnimate];
[UIView animateKeyframesWithDuration:2.0 delay:0.0 options:UIViewKeyframeAnimationOptionCalculationModeLinear | UIViewAnimationOptionCurveEaseInOut|UIViewAnimationOptionRepeat|UIViewAnimationOptionAutoreverse animations:^{
[objAnimate setAlpha:0.0];
} completion:nil];
The view starts animating as soon as its added in your view.
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];
}];
I'm trying to flip animate a view into another view, which corresponds of a small section of the screen. Both views have the same dimensions and center.
I keep getting as a result the animation of the full screen. From the code below, can somebody please let me know what the heck i'm doing wrong?
Thank you,
-j
+ (void) flipView:(UIView*)viewA toView:(UIView*)viewB wait:(Boolean)wait
{
// get parent view
UIView *parent = [viewA superview];
CGRect r = viewA.frame;
// create container view with the same dimensions as ViewA
UIView *containerView = [[UIView alloc] initWithFrame:viewA.bounds];
containerView.center = viewA.center;
// attache both views to intermidiate view
[containerView addSubview:viewA];
[containerView addSubview:viewB];
[viewA removeFromSuperview];
[parent addSubview:containerView];
viewB.alpha = 0;
viewA.alpha = 1;
// Perform the annimation
__block BOOL done = NO;
[UIView transitionWithView:viewA
duration:2.0
options: (UIViewAnimationOptionTransitionFlipFromTop)
animations:^{
viewA.alpha = 0;
viewB.alpha = 1; }
completion:^(BOOL finished) {
done = YES;
// detach all views
[viewA removeFromSuperview];
[viewB removeFromSuperview];
[containerView removeFromSuperview];
}
];
if(wait) {
while (done == NO)
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}
}
First get rid of the old animation code (or at least commit it), it should look like this:
+ (void) flipView:(UIView*)viewA toView:(UIView*)viewB wait:(BOOL)wait
{
viewB.alpha = 0;
viewA.alpha = 1;
__block BOOL done = NO;
[UIView transitionWithView:viewA
duration:2.0
options: (UIViewAnimationOptionTransitionFlipFromTop)
animations:^{
viewA.alpha = 0;
viewB.alpha = 1; }
completion:^(BOOL finished) {
done = YES;
}
];
if(wait) {
while (!done)
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}
}
Second, the superview of the subview that you want to transition is actually going to get the transition. So this means that you'll have to add viewA and viewB to a subview, add this subview to another view and then do the animation.
Here is a solution without any hacks with runloop. Just use the first message to run a transition to another view, and the second message to return to original state:
- (void) forwardTransitionFromView: (UIView *) viewA toView: (UIView *) viewB
{
NSAssert(viewA.superview, #"The 'from' view should be added to a view hierarchy before transition");
NSAssert(!viewB.superview, #"The 'to' view should NOT be added to a view hierarchy before transition");
CGSize viewASize = viewA.bounds.size;
viewB.frame = CGRectMake(0.0, 0.0, viewASize.width, viewASize.height);
[UIView transitionWithView:viewA
duration:1.0
options:UIViewAnimationOptionTransitionFlipFromRight
animations:^{
[viewA addSubview:viewB];
}
completion:NULL];
}
- (void) backwardTransitionFromView: (UIView *) viewB toView: (UIView *) viewA
{
NSAssert([viewB.superview isEqual:viewA], #"The 'from' view should be a subview of 'to' view");
[UIView transitionWithView:viewA
duration:1.0
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{
[viewB removeFromSuperview];
}
completion:NULL];
}
Why dont you flip both views in same direction?
-(void) FlipView:(bool) fromRight {
if(fromRight) {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.75];
[UIView setAnimationDelegate:self];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:view1 cache:YES];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:view2 cache:YES];
[UIView commitAnimations];
}
else {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.75];
[UIView setAnimationDelegate:self];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:view1 cache:YES];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:view2 cache:YES];
[UIView commitAnimations];
}
}
and call the method like below:
[view1 setHidden:NO];
[self FlipView:YES];
[view2 setHidden:YES];
to reverse the animation:
[view2 setHidden:NO];
[self FlipView:NO];
[view1 setHidden:YES];
I have a View (CupsViewController) with a Label and when it's clicked, TableView (AddressTableController) slides from the bottom of the screen and stays in the lower half.
In TableView, when Ok Buttonis pressed, I want to change value of Labeland remove TableViewwith animation (that is, slide to the bottom).
Here is my code:
CupsViewController
Method called when click on Label
- (IBAction)showPop:(id)sender
{
addressTableController = [[AddressTableController alloc]initWithStyle:UITableViewStyleGrouped];
[addressTableController setDelegate:self];
[[self view] addSubview:[addressTableController myTableView]];
[UIView animateWithDuration:1.0 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
[[addressTableController myTableView] setFrame:CGRectMake(0, kScreenHeight * 0.5, kScreenWidth, kScreenHeight * 0.5)];
} completion:nil];
}
Method called from AddressTableControllerwhen Buttonis pressed
- (void)addressTableController:(AddressTableController *)viewController didChooseValue:(int)value {
direccionLabel.text = [[[[myAppDelegate usuarioActual] cups] objectAtIndex:value] direccion];
[addressTableController.view removeFromSuperview];
}
Image
As you can see, I've tried with removeFromSuperviewbut it does nothing. How can I slide TableViewto the bottom?
It seems that you myTableView property returns a different view, not the one that is referenced in the view property. So you basically add the former as a subview ([[self view] addSubview:[addressTableController myTableView]];), but try to remove the latter ([addressTableController.view removeFromSuperview];).
Just do
[[addressTableController myTableView] removeFromSuperview];
instead of
[addressTableController.view removeFromSuperview];
Here you go. Cheers, mate! :)
P.S.
if you want to animate the view out, you can do it like this
[UIView animateWithDuration:1.0 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
// animation code...
} completion:^(BOOL finished) {
[[addressTableController myTableView] removeFromSuperview];
}];
In my app, I have a scrollview with "paging enabled" and when I chose a page an imageview start its animation in this way
- (void) beginWinAnimation{
[UIView animateWithDuration:2.5
animations:^{successView.alpha = 1.0;}
completion:^(BOOL finished){
[UIView animateWithDuration:2.5
animations:^{successView.alpha = 0;}];
}];}
During this animation I can see the scrollview under this successView and I can move scrollview page; I want that during animation you can't move the scrollview but only when animation is finished, is it possible?
Yes it's possible. When the animation starts set [scrollView setScrollEnabled:NO]; After your animation is complete set it back to YES.
So in your code, it will look like -
- (void) beginWinAnimation{
[scrollView setScrollEnabled:NO];
[UIView animateWithDuration:2.5
animations:^{
successView.alpha = 1.0;
}
completion:^(BOOL finished){
[UIView animateWithDuration:2.5
animations:^{successView.alpha = 0;}
completion:^(BOOL finished){
[scrollView setScrollEnabled:YES];
}];
}];}
See if this works.