UIView Animation Curves not working for some animations - ios

I have an app in which I use a lot of animations with ease in/out curves. I use this function in all cases: UIView animateWithDuration:delay:options:animations:completion
All these animations are working ok, but now I am trying to add one to a drawer that pops in and out, and for some reason this particular animation is always linear:
[UIView animateWithDuration:2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.activityBar.view.frame = CGRectMake(0, self.activityBar.view.frame.origin.y, self.activityBar.view.frame.size.width, 20);
} completion:nil];
Why is this animation linear, while other animations with the same option are curved?
This is the view hierarchy for self.activityBar.view
-UIViewController
-UIViewController
-UIViewController (animation code lives here)
-UIViewController (activityBar)
-UIView (activityBar.view)

//Set old Frame for activityBar Here
[UIView animateWithDuration:2.0 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[self.view layoutIfNeeded];
//Update to the new frame
self.activityBar.view.frame = CGRectMake(0, self.activityBar.view.frame.origin.y, self.activityBar.view.frame.size.width, 20);
} completion:^(BOOL finished) {
}];

Related

Animation does not seem to work - move view from one position to another on [self dismissViewController

I have a view currently on the screen and I would like to move it off the screen during an animation. Its current position is: CGRectMake(0, 168, 320, 50); and I would like to move it to y postion 218.
Here is my code:
[UIView beginAnimations:Nil context:NULL];
[UIView setAnimationDuration:0.3];
self.optionsView.frame = CGRectMake(0, 218, 320, 50);
[UIView commitAnimations];
Thanks in advance. Nothing is happening, the view isnt moving off screen.
Edit: When the app launches the view is off screen, i then call:
[UIView beginAnimations:Nil context:NULL];
[UIView setAnimationDuration:0.3];
self.optionsView.frame = CGRectMake(0, 168, 320, 50);
[UIView commitAnimations];
to bring the view into the main view. The problem I have is making the view go back off screen again with:
[UIView beginAnimations:Nil context:NULL];
[UIView setAnimationDuration:0.3];
self.optionsView.frame = CGRectMake(0, 218, 320, 50);
[UIView commitAnimations];
It must be noted that in order to get the view to be off screen on app launch I call:
-(void) viewDidLayoutSubviews{
self.optionsView.frame = CGRectMake(0, 218, 320, 50);
}
Update: I am also using the camera, i think dismissing the camera is affecting the layouts
I've animated the position of views as follows:
// 'frame' variable previously declared
// 'completion' block previously declared
[UIView animateWithDuration:0.3f
delay:0.0f
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
[_someView setFrame:frame];
}
completion:^(BOOL finished){
if (completion) {
completion();
}
}];
Have you tried it that way?
As Martin Koles has said, the block-based approach to view animation is preferred. The following is in the reference doc for UIView:
Use of the methods in this section is discouraged in iOS 4 and later.
Use the block-based animation methods instead.
https://developer.apple.com/library/ios/documentation/uikit/reference/uiview_class/UIView/UIView.html
Use block instead:
[UIView transitionWithView:self.view duration:0.3 options:UIViewAnimationOptionCurveEaseInOut animations:^{
// final view elements attributes goes here
} completion:nil];
This is the modern way of doing animations. You can even specify a completion block, something that should happed after the animation is done, if needed.
Try using this
[UIView animateWithDuration:0.3 delay:0 options: UIViewAnimationOptionCurveLinear
animations:^{
self.optionsView.frame = CGRectMake(0, 218, 320, 50);
} completion:nil];
Worked fine with me.
Make sure the view is connected in the xib to its proper object.

animateWithDuration setFrame not working

Hi I have piece of code which only one line is not working...
[UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[label setFrame:CGRectMake(0, 0, frame.size.width, kStandardLabelHeight)]; //working
[self.currentLabel setFrame:CGRectOffset(self.currentLabel.frame, frame.size.width, 0)]; //not working
[self.currentLabel setAlpha:0.0f]; //working
} completion:^(BOOL finished) {
[self.currentLabel removeFromSuperview];
self.currentLabel = label;
}];
I'm running out of ideas what is wrong...
What I find out is: if I turn off "Use Auto Layout", then it magically working, so this issue is connected with auto layout.
After a search, I find this: http://weblog.invasivecode.com/post/42362079291/auto-layout-and-core-animation-auto-layout-was
Add constraint outlet mapping for your view, then instead of using setFrame, updating constraints will do the trick!
Below is my final implementation (_topConstraint is the top vertical space constraint of table view):
- (IBAction)switchButtonTouched:(id)sender
{
if (_topConstraint.constant <= 0)
_topConstraint.constant = _buttonView.frame.size.height;
else
_topConstraint.constant = 0;
[_tableView setNeedsUpdateConstraints];
[UIView animateWithDuration:0.5f animations:^(void){
[_tableView layoutIfNeeded];
} completion:^(BOOL finished){
}];
}
Frame must be a CGRect with 4 parameters: (xPosition,yPosition,width,height). Use CGRectMake for set frame
self.currentLabel.frame = CGRectMake(100, 100, self.currentLabel.frame.size.width, self.currentLabel.frame.size.height)
You set 0.3 sec the animation duration, and when it s end you remove it from the view. This is too short. set the duration for example 2, and you will see that your label is moving .
Sometimes you should set frames for animating views also after animation, for example in completion block, try something like that
[UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[label setFrame:CGRectMake(0, 0, frame.size.width, kStandardLabelHeight)]; //working
[self.currentLabel setFrame:CGRectOffset(self.currentLabel.frame, frame.size.width, 0)]; //not working
[self.currentLabel setAlpha:0.0f]; //working
} completion:^(BOOL finished) {
self.frame = currentLabelFrame;
label.frame = label.frame;
[self.currentLabel removeFromSuperview];
self.currentLabel = label;
}];
If your issue is neither Autolayout related, or the others listed here, there is also another possible problem that turned out to be my issue. I'm simultaneously running a UIView transition (transitionFromView:toView:) on views that take up the same screen space (Different superviews, not related, other than positioning in the superview of the overarching view controller).
My code looked like this:
[UIView transitionFromView:self.someView
toView:self.someOtherView
duration:0.6f
options:UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionShowHideTransitionViews
completion:NULL];
[UIView animateWithDuration:0.3
delay:0.0 options:UIViewAnimationOptionCurveEaseOut
animations:^{
[self.someThirdView setFrame:someFrame]; //not working
[self.someThirdView setAlpha:1.0f]; //working
} completion:nil];
The frame changed, but it popped to the new frame rather than animating. I'm guessing this is an internal iOS issue. As soon as I removed the "transitionFromView:..." call, the frame animation worked fine.
My solution for now has been to move the second animation into the completion block of the transitionFromView. It's not perfect, as the two animations should have lined up, but it is a passable solution for now.

Apply some easing into UIImageView animation

I am using the following to make a UIImageView slide a little bit forward, and then slide back farther for a parallax scrolling effect.
Code:
[UIView animateWithDuration:0.2f animations:^{
spendrBckGrnd.frame = CGRectMake(spendrBckGrnd.frame.origin.x + 20, 0, spendrBckGrnd.frame.size.width, spendrBckGrnd.frame.size.height);
}];
[UIView animateWithDuration:0.4f animations:^{
spendrBckGrnd.frame = CGRectMake(spendrBckGrnd.frame.origin.x - 80, 0, spendrBckGrnd.frame.size.width, spendrBckGrnd.frame.size.height);
}];
I am wondering how I might go about applying some easing into the animation, right now if just abruptly slides back and forth quickly. I would like to ease into and out of the sliding animations.
You need to do the second animation block after the first one completes.
[UIView animateWithDuration:0.2f animations:^{
spendrBckGrnd.frame = CGRectMake(spendrBckGrnd.frame.origin.x + 20, 0, spendrBckGrnd.frame.size.width, spendrBckGrnd.frame.size.height);
} completion:^{
[UIView animateWithDuration:0.2f animations:^(BOOL finished){
spendrBckGrnd.frame = CGRectMake(spendrBckGrnd.frame.origin.x - 80, 0, spendrBckGrnd.frame.size.width, spendrBckGrnd.frame.size.height);
}];
}];
This will do the trick:
[UIView animateWithDuration:0.2f delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^(void){
//do your animations
} completion:^(BOOL finished){
}];
Check out this tutorial on UIView animation
http://mobile.tutsplus.com/tutorials/iphone/ios-sdk_uiview-animations/
UIView has a method
// [UIView animateWithDuration:(NSTimeInterval) delay:(NSTimeInterval) options:(UIViewAnimationOptions)animations:^(void)animations completion:^(BOOL finished)completion];
typedef enum {
UIViewAnimationCurveEaseInOut, // slow at beginning and end
UIViewAnimationCurveEaseIn, // slow at beginning
UIViewAnimationCurveEaseOut, // slow at end
UIViewAnimationCurveLinear
}
[UIView animateWithDuration:0.6f
delay:0.1f
options:UIViewAnimationCurveEaseInOut
animations:^{
[starView setCenter:CGPointMake(0, 0)];
[starView setAlpha:0.0f];
}
completion:^(BOOL finished){
[starView removeFromSuperview];
points++;
}
];
Also check out this control on github that creates a parallax effect using a custom container view, much like the top view of Path's timeline.
https://github.com/modocache/MDCParallaxView

An example of how UIViewAnimationOptionLayoutSubviews works?

Apple's documentation describes UIViewAnimationOptionLayoutSubviews as:
Lay out subviews at commit time so that they are animated along with
their parent.
Here is a sample of the code I'm interested in. I wish to animate the -layoutSubviews of detailView; however, it doesn't seem to layout the subviews of detailView, so I'm not sure what effect it actually has.
void (^animation) () = ^
{
[self.detailView setNeedsLayout];
[self.detailView layoutIfNeeded];
};
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionLayoutSubviews
animations:^{
animation();
}
completion:nil];
Since you want your second animation to occurs from the current state of your first animation (whether it is finished or not) I recommend to use the UIViewAnimationOptionLayoutSubviews option when setting your second animation.
[UIView animateWithDuration:0.2
delay:0.0
options:UIViewAnimationOptionLayoutSubviews
animations:^{
CGAffineTransform settingsTransform = CGAffineTransformMakeTranslation(self.animatedView.frame.size.width, 0);
self.animatedView.transform = settingsTransform;
}
completion:nil];

UILabel disappears after animateWithDuration

I've got a UILabel that slides in and out of view, but after it slides back in it disappears. I want it to persist.
How can I achieve this? Also, why does this happen?
Here's the code:
[UIView animateWithDuration:0.1
delay:0.0
options:UIViewAnimationOptionAutoreverse
animations:^{
[self.listLabel setFrame:CGRectMake(325, 141, 320, 181)];
}
completion:nil];
Thanks.
In official documentation
UIViewAnimationOptionAutoreverse
Run the animation backwards and forwards. Must be combined with the UIViewAnimationOptionRepeat option.
Why don't you use UIViewAnimationOptionCurveEaseOut and UIViewAnimationOptionCurveEaseIn animation option for your label?
Just set your label's frame.origin.x = [outside the right side of it's superview's bound]
and set it back to it's original position when you want to slide-In again using EasyOut animation.
Here's something what I'm talking about...
CFRect frame = self.listLabel.frame;
//Point to hide your label by sliding it outside the right side of it's parent's view.
// mask or clipToBounds of parent's view must be YES
frame.origin.x = [self.listLabel.superview.frame.size.width];
[UIView animateWithDuration:0.1
delay:0.0
options:UIViewAnimationOptionCurveEaseIn
animations:^{
[self.listLabel setFrame:frame];
}
completion:nil];
And When you want to slide back in, use opposite animation and label's original position, of course you need to store it's original position somewhere so you could slide-in it back.
[UIView animateWithDuration:0.1
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
[self.listLabel setFrame:label_original_frame];
}
completion:nil];
UIViewAnimationOptionAutoreverse is designed for a cyclical animation. To just bounce something offscreen and back, you should just write it as 2 animations:
CGRect originalFrame = self.listLabel.frame;
[UIView animateWithDuration:0.05
delay:0.0
options:UIViewAnimationOptionLayoutSubviews
animations:^{
[self.listLabel setFrame:CGRectMake(325, 141, 320, 181)];
}
completion:^(BOOL finished){
[UIView animateWithDuration:0.05
delay:0.0
options:UIViewAnimationOptionLayoutSubviews
animations:^{
[self.listLabel setFrame:originalFrame];
}
completion:nil];
}
];
As there still seems to be no valid answer, I propose a (now possible) approach:
In Xcode 6, with the app running in the simulator, go to "Debug" in the top bar, select "View Debugging" and "Capture View Hierarchy". Then go and search your missing Label. You can also see properties etc. of the Label in the right Xcode bar.

Resources