How to use setAnimationStartDate?
The following code does not work.
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:3.0];
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:3];
[UIView setAnimationStartDate:date];
CGPoint point = _imageView.center;
point.y += 150;
[_imageView setCenter:point];
[UIView commitAnimations];
You could use block-based animations. They are much cleaner and can do exactly what you need. One method to look at is +[UIView animateWithDuration:delay:options:animations: completion:]. The delay parameter would be useful in your situation. Here is an example.
[UIView animateWithDuration:10
delay:3
options:UIViewAnimationOptionCurveEaseIn
animations: ^{
CGPoint point = _imageView.center;
point.y += 150;
[_imageView setCenter:point];
}
completion: ^(BOOL finished) {
NSLog(#"Animation Complete");
}];
You may have to mess around with the delay to mimic your NSDate setup.
Related
I am trying to make an image start at coordinates x=80 and y=249 which would move to x=284 and y=99. Then from there it would go to x=488 and y=249.
This is what i got, but for some reason the image starts at x=284 and y=99 and moves to x=488 and y=249.
I need help to fix this issue.
-(void)BallArchR{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 1.5];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
CGPoint center = [Ball center];
center.x = 284;
center.y = 99;
[Ball setCenter:center];
[UIView commitAnimations];
[self BallArchR2];
}
-(void)BallArchR2{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 1.5];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
CGPoint center = [Ball center];
center.x = 488;
center.y = 249;
[Ball setCenter:center];
[UIView commitAnimations];
}
because of you call BallArchR2 method from BallArchR method directly. But in actual, the animation of BallArchR method is not complete and before that BallArchR2 method is called. So, call BallArchR2 method after the completion of first BallArchR method animation. So you can Try this hope it helps you:
-(void)BallArchR{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 1.5];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
CGPoint center = [Ball center];
center.x = 284;
center.y = 99;
[Ball setCenter:center];
[UIView commitAnimations];
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 1.55 * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self BallArchR2];
});
}
-(void)BallArchR2{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 1.5];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
CGPoint center = [Ball center];
center.x = 488;
center.y = 249;
[Ball setCenter:center];
[UIView commitAnimations];
}
I have a problem using a slider to trigger a series of animations, here's the code:
-(void)slideAlpha:(id)sender{
self.bigPhotoViewA.alpha = self.alphaSlider.value;
if (self.alphaSlider.value == 1){
[UIView animateWithDuration:1
animations:^{
self.alphaSlider.alpha = 0;
} completion:nil
];
[self performSelector:#selector(nextPhotoAnimation) withObject:self afterDelay:5.0 ];
}
}
-(void) nextPhotoAnimation{
self.alphaSlider.value = 0;
[UIView animateWithDuration:2
animations:^{
self.bigPhotoViewA.alpha = 0.0;
self.bigPhotoView.alpha = 0.0;
self.smallPhotoView.center = CGPointMake(startX, startY);
}
completion:^(BOOL finished) {
NSLog(#"Animation ended");
self.smallPhotoView.image = ((UIImage *)[smallImagesArray objectAtIndex:imageCount]);
}
];
}
So, when the slider reaches a value of 1, nextPhotoAnimation is launched after a delay. So far so good. The problem comes inside nextPhotoAnimation. The animations block runs ok, but the completion block runs several times every time nextPhotoAnimation is called. I get the NSLog from 6 to 9 times displayed when nextPhotoAnimation starts, and then I get it again at the right time, after 2 seconds.
I've tried to replicate the problem with simpler code and the animation/completion flow works just fine.
Try this in nextPhotoAnimation,
-(void) nextPhotoAnimation{
self.alphaSlider.value = 0;
[UIView animateWithDuration:2
animations:^{
self.bigPhotoViewA.alpha = 0.0;
self.bigPhotoView.alpha = 0.0;
self.smallPhotoView.center = CGPointMake(startX, startY);
}
completion:^(BOOL finished) {
if (finished) {
NSLog(#"Animation ended");
self.smallPhotoView.image = ((UIImage *)[smallImagesArray objectAtIndex:imageCount]);
}
}
];
}
neither you are using
[UIView beginAnimations:nil context:nil];
nor
[UIView commitAnimations];
Best way is to create a UIView and then use the protocols.call your methods using [self YOURMETHOD]; in the View.
:-)
Here's the code I'm using to take a UIImageView and make it float up and down.
[UIView animateKeyframesWithDuration:2.0 delay:0.0 options:UIViewKeyframeAnimationOptionRepeat animations:^{
[UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.25 animations:^{
self.slider.transform = CGAffineTransformMakeTranslation(0, -5.0);
}];
[UIView addKeyframeWithRelativeStartTime:0.25 relativeDuration:0.5 animations:^{
self.slider.transform = CGAffineTransformMakeTranslation(0, 5.0);
}];
[UIView addKeyframeWithRelativeStartTime:0.75 relativeDuration:0.25 animations:^{
self.slider.transform = CGAffineTransformMakeTranslation(0, 0.0);
}];
} completion:^(BOOL finished) {
}];
However, it comes out looking like this with this delay after the animation ends and before it restarts.
How do I make it fluid?
I'm not sure what effect you're going for exactly, but I think this gives you something like your code does without the delay. I usually do this by animating a constraint, rather than using transforms. In this example, I've made an IBOutlet (topCon) to the constraint to the top of the view:
-(IBAction)floatView:(id)sender {
static int i= 1;
static float duration = .25;
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
self.topCon.constant = self.topCon.constant - (5 * i);
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
i = (i == 1 || i == 2)? -2 : 2;
duration = 0.5;
[self floatView:self];
}];
}
I am trying to use a UIView animation to simply move a view onto the screen:
[UIView animateWithDuration:.10 delay:0 options: nil animations:^
{
self.menusView.frame = endingMenuViewFrame;;
}
completion:^(BOOL finished)
{
}];
I'm wanting to add an animation so that UIView floats a little when it reaches the top before it comes down, i.e. akin to if someone jumps in the air - when they first jump, they shoot up quickly, but then gravity gradually slows them down as they reach the top of their jump, and eventually it pushes them back to earth. Does anyone know how to accomplish this?
Try with this code. This will make your view bounce three times with each time your height reduced by half. You may add more bounces.
CGFloat offset = 200.0;
CGRect originalFrame = self.menusView.frame;
[UIView animateWithDuration:1.0 animations:^{
CGRect frame = self.runnerAlertView.frame;
frame.origin.y = frame.origin.y - offset;
self.menusView.frame = frame;
} completion:^(BOOL finished){
[UIView animateWithDuration:1.0 animations:^{
self.menusView.frame = originalFrame;
} completion:^(BOOL finished) {
[UIView animateWithDuration:1.0 animations:^{
CGRect frame = self.menusView.frame;
frame.origin.y = frame.origin.y - 0.5 *offset;
self.menusView.frame = frame;
} completion:^(BOOL finished){
[UIView animateWithDuration:1.0 animations:^{
self.menusView.frame = originalFrame;
} completion:^(BOOL finished) {
[UIView animateWithDuration:1.0 animations:^{
CGRect frame = self.runnerAlertView.frame;
frame.origin.y = frame.origin.y - 0.25 * offset;
self.menusView.frame = frame;
} completion:^(BOOL finished){
[UIView animateWithDuration:1.0 animations:^{
self.menusView.frame = originalFrame;
}];
}];
}];
}];
}];
}];
I use the following block of code to slide a UIView down and when finished rotate another UIView.
The second part of the animation, the completion block is only performed once which means the 1st animation is not completed else it would reach the completion block.
On the iphone simulator it looks as if the 1st animation did finish...
can anyone help me figure this out?
my NSLog says:
finished 1st
started 2nd
finished 1st
finished 1st
finished 1st
.
.
.
- (IBAction) move
{
[UIView animateWithDuration:0.7 animations:^{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.7];
[UIView setAnimationRepeatCount:1];
[UIView setAnimationRepeatAutoreverses:NO];
CGPoint pos = movingtTable.center;
float moveDistance = 220.0;
if(!isViewVisible){
//expose the view
pos.y = pos.y+moveDistance;
//disable selection for xy table
xTable.userInteractionEnabled = NO;
yTable.userInteractionEnabled = NO;
//angle = M_PI;
}
else
{
pos.y = pos.y-moveDistance;
xTable.userInteractionEnabled = YES;
yTable.userInteractionEnabled = YES;
//angle = -M_PI;
}
isViewVisible = !isViewVisible;
movingtTable.center = pos;
NSLog(#"finished 1st");
}completion:^(BOOL finished){
NSLog(#"started 2nd");
[UIView animateWithDuration:0.4 animations:^{
//[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.4];
//[UIView setAnimationRepeatCount:1];
//[UIView setAnimationRepeatAutoreverses:NO];
arrows.transform = CGAffineTransformMakeRotation(angle);
}completion:^(BOOL finished){
angle = -angle;
}];
}];
Why are you trying to initialize another UIView animation inside the animateWithDuration block code? Update your code to the following and make sure you're not performing multiple animations of a single view at a time.
- (IBAction) move
{
[UIView animateWithDuration:0.7 animations:^{
CGPoint pos = movingtTable.center;
float moveDistance = 220.0;
if(!isViewVisible){
//expose the view
pos.y = pos.y+moveDistance;
//disable selection for xy table
xTable.userInteractionEnabled = NO;
yTable.userInteractionEnabled = NO;
//angle = M_PI;
}
else
{
pos.y = pos.y-moveDistance;
xTable.userInteractionEnabled = YES;
yTable.userInteractionEnabled = YES;
//angle = -M_PI;
}
isViewVisible = !isViewVisible;
movingtTable.center = pos;
NSLog(#"finished 1st");
}
completion:^(BOOL finished){
NSLog(#"started 2nd");
[UIView animateWithDuration:0.4 animations:^{
arrows.transform = CGAffineTransformMakeRotation(angle);
}completion:^(BOOL finished){
angle = -angle;
}];
}];
BTW: The block code requires some serious refactoring, if you ask me :)
You are mixing and matching paradigms and I believe that is causing the issue you are seeing. You are creating an animation block, but inside of that block you are creating a new animation routine with the 'old' paradigm for running UIView animations. Apple is leading people away from the old paradigm and I would encourage you to ONLY use blocks as well.
This is why the completion block only runs once, the UIView animateWith block code only runs once. However, your internal animation code runs multiple times.
Take out:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.7];
[UIView setAnimationRepeatCount:1];
[UIView setAnimationRepeatAutoreverses:NO];
If you want your animation block to run several times, then use the full method:
animateWithDuration:delay:options:animations:completion:
Make the delay = 0, and set your options to UIViewAnimationOptionRepeat, or whatever you need to accomplish the number of cycles you want the block to complete.
Here is my suggestion assuming you want it to repeat:
- (IBAction) move
{
[UIView animateWithDuration:0.7
delay:0
options:UIViewAnimationOptionRepeat
animations:^{
CGPoint pos = movingtTable.center;
float moveDistance = 220.0;
if(!isViewVisible) {
//expose the view
pos.y = pos.y+moveDistance;
//disable selection for xy table
xTable.userInteractionEnabled = NO;
yTable.userInteractionEnabled = NO;
//angle = M_PI;
}
else {
pos.y = pos.y-moveDistance;
xTable.userInteractionEnabled = YES;
yTable.userInteractionEnabled = YES;
//angle = -M_PI;
}
isViewVisible = !isViewVisible;
movingtTable.center = pos;
NSLog(#"finished 1st");
}
completion:^(BOOL finished){
NSLog(#"started 2nd");
[UIView animateWithDuration:0.4
animations:^{
arrows.transform = CGAffineTransformMakeRotation(angle);
}
completion:^(BOOL finished){
angle = -angle;
}];
}];
}