Fade in and fade out a UIView while it is moving - ios

It's easy enough to animate the view:
[UIView animateWithDuration:1.0
animations:^{theView.center = newCenter; theView.alpha = 0;}
completion:^(BOOL finished){
[theView removeFromSuperview];
}];
The problem is that when I add it as a subview, I want it to fade in and already look like it is moving. Right now it appears immediately, then moves and fades out.
So, I need to set it's initial alpha to zero, fade it quickly while it is moving, then fade it out. Is this possible with UIView animations? I can't have two competing animation blocks working on the same object right?

All you need to do is apply 2 animations back-to-back. Something like this ::
theView.alpha = 0;
[UIView animateWithDuration:1.0
animations:^{
theView.center = midCenter;
theView.alpha = 1;
}
completion:^(BOOL finished){
[UIView animateWithDuration:1.0
animations:^{
theView.center = endCenter;
theView.alpha = 0;
}
completion:^(BOOL finished){
[theView removeFromSuperview];
}];
}];
So in the 1st second it will appear while moving and then in the next second it will fade out
Hope this helps

Put the initial alpha=0 outside animation block.
theView.alpha = 0;
[UIView animateWithDuration:1.0
animations:^{
theView.center = newCenter;
theView.alpha = 1;
}
completion:^(BOOL finished){
// Do other things
}];

Related

How to repeat shake animation indefinitely or X times using animateWithDuration?

The code below came from this SO question: UIView shake animation.
This shake animation is perfect, except it stops after one iteration. How do you repeat the animation indefinitely, or how do you cause it to repeat it X times?
There are other SO answers on repeating UIView animations that suggest using CAKeyframeAnimation or CABasicAnimation, but this question is different. The goal is to reproduce this exact animation, with the "springy" effect from usingSpringWithDamping and initialSpringVelocity.
Using Autoreverse and Repeat don't reproduce the desired effect because the the initial translation is outside the animation block.
view.transform = CGAffineTransformMakeTranslation(20, 0);
[UIView animateWithDuration:0.4 delay:0.0 usingSpringWithDamping:0.2 initialSpringVelocity:1.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
view.transform = CGAffineTransformIdentity;
} completion:nil];
If you need exact same code few times than put that code in method and do recursion, something like that:
- (void)animateCount:(NSInteger)count {
if (count == 0) {
return;
}
view.transform = CGAffineTransformMakeTranslation(20, 0);
[UIView animateWithDuration:0.4 delay:0.0 usingSpringWithDamping:0.2 initialSpringVelocity:1.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
view.transform = CGAffineTransformIdentity;
} completion:^{
count--;
[self animateCount:count];
}];
}
Use (UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeat) in options to repeat it indefinitely
[UIView animateWithDuration:0.4 delay:0.0 usingSpringWithDamping:0.2 initialSpringVelocity:1.0 options:(UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeat | UIViewAnimationOptionCurveEaseInOut) animations:^{
someView.frame = someFrame1;
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.5f animations:^{
someView.frame = someFrame2;
} completion:nil];
}];

Smoothest Way To Implement Back to Back UIAnimations

I need to have my character jump (increase the origin.y by 50 and reverse) in a game I am creating.
So far I have come across two ways of doing this:
Method 1:
[UIView animateWithDuration:1.0
delay:0.0
options:UIViewAnimationOptionAutoreverse
animations:^{
CGRect frame = self.kevinImageView.frame;
frame.origin.y -= 50;
self.kevinImageView.frame = frame;
} completion:^(BOOL finished){
CGRect frame = self.kevinImageView.frame;
frame.origin.y = 135;
self.kevinImageView.frame = frame;
}];
Issues: At the end of every complete jump animation (up and down) the ImageView jumps up and then back down (due probably to the tiny amount it takes for the completion block to be called). This is noticeable and I would much rather do without it.
Method 2:
[UIView animateWithDuration:1.0
animations:^{
CGRect frame = self.kevinImageView.frame;
frame.origin.y -= 50;
self.kevinImageView.frame = frame;
} completion:^(BOOL finished){
[UIView animateWithDuration:1.0
animations:^{
CGRect frame = self.kevinImageView.frame;
frame.origin.y += 50;
self.kevinImageView.frame = frame;
}];
}];
Issues: If I tap the view (I use a UITapGuestureRecognizer) and the ImageView is in the completion animation (going back down), the Image View will snap back to the bottom instead of finishing its animation. Again not a major issue, but something which I should be able to avoid.
Is there any method I have not come across which will resolve both of these issues, or a way to fix one of the methods?
Can you disable your UITapGuestureRecognizer when the animation is still running? And then enable it when the animation finishes.
if (!self.isAnimationRunning) {
self.isAnimationRunning = YES;
[UIView animateWithDuration:1.0
animations:^{
CGRect frame = self.kevinImageView.frame;
frame.origin.y -= 50;
self.kevinImageView.frame = frame;
} completion:^(BOOL finished){
[UIView animateWithDuration:1.0
animations:^{
CGRect frame = self.kevinImageView.frame;
frame.origin.y += 50;
self.kevinImageView.frame = frame;
} completion:^(BOOL finished){
self.isAnimationRunning = NO;
}];
}];
}
I'm very interested in this question so I do a simple demo to do a back to back animation.
I think maybe you can just use UIViewAnimationOptionAutoreverse and UIViewAnimationRepeat option to achieve a autoreverse animation.
[UIView animateWithDuration:1.0
delay:0
options:UIViewAnimationOptionAutoreverse|UIViewAnimationRepeat
animations:^{
[UIView setAnimationRepeatCount:1];
self.kevinImageView.center = CGPointMake(self.kevinImageView.center.x ,self.kevinImageView.center.y - 25);
} completion:^(BOOL finished){
self.kevinImageView.center = CGPointMake(self.kevinImageView.center.x ,self.kevinImageView.center.y + 25);
}];
and you can also set UIViewAnimationOptionAllowUserInteraction if you want to enable use interaction during the animation.

When creating an animation to cause a UIImageView to go up and down (almost float) infinitely, how do I stop a pause at the end of the animation?

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];
}];
}

Animating UIView alpha according to views location

I am animating a view using this code but would like to set the alpha of the orb according to its location . is this possible as I understand that the animation block is executed immediately and I have no access to its location
self.orbView.center = self.arrowView.center;
self.orbView.alpha = 1;
[UIView animateWithDuration:1.0 delay:0 options:UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeat animations:^{
self.orbView.center = CGPointMake(arrowCornerRight,self.orbView.center.y);
self.orbView.alpha = 0;
} completion:^(BOOL finished) {
}];

IOS Animation not working with my animation block

Im Trying to make a red square move from top of view to a random position at the bottom of the view and the return to the top again at random position.
The app starts with the following code into [super viewLoad]:
[redSquare setCenter:CGPointMake(25,25)];
(with the red square view set 50 x 50, this starts the app with the redsquare in the top left corner).
The first part of the animation works well - the red square animates to a random position to the bottom of the page. But, it then jumps to a random position to the top without animation.
Please help what I'm doing wrong or any other solutions to help with this simple animation.
-(void)moving{
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseIn animations:^{
int randomx = arc4random() % 295;
[redSquare setCenter:CGPointMake(randomx,435)];
} completion:^(BOOL finished) {
[redSquare setCenter:CGPointMake(redSquare.frame.origin.x,25)];
}];
}
Your completion block simply sets the new position. You aren't animating it back to the top:
Try this, instead
-(void)moving {
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseIn animations:^{
int randomx = arc4random() % 295;
[redSquare setCenter:CGPointMake(randomx,435)];
} completion:^(BOOL finished) {
[UIViewAnimateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseIn animations:^{
[redSquare setCenter:CGPointMake(redSquare.frame.origin.x,25)];
} completion: NULL
}];
}
Edited to add
It's true that sublevels can get confusing, but you can make life simple and less indented if you define the blocks separately from the method.
For example, you could rewrite the above as:
-(void)moving {
workBlk_t animationBlock = ^ {
int randomx = arc4random() % 295;
[redSquare setCenter:CGPointMake(randomx,435)];
};
void (^completionBlock)(BOOL finished) = ^{
[UIViewAnimateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseIn animations:^{
[redSquare setCenter:CGPointMake(redSquare.frame.origin.x,25)];
} completion : NULL
};
[UIView animateWithDuration:1.0
delay:0.0
options:UIViewAnimationCurveEaseIn
animations:animationBlock
completion:completionBlock
}];
}
you should start new animation in completion block for example:
completion:^(BOOL finished) {
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseIn animations:^{
int randomx = arc4random() % 295;
[redSquare setCenter:CGPointMake(randomx,25)];
} completion:^(BOOL finished) {
}];
}];
This part does exactly what you are describing:
completion:^(BOOL finished) {
[redSquare setCenter:CGPointMake(redSquare.frame.origin.x,25)];
}
I.e. returns the object to the top of the screen after the animiation is completed. This will not be animated, it will happen after the animation is completed, and thus it will be instant.
You need to trigger a new animation after the animation is completed.
To create several nested animation blocks can however become a bit messy, the most clean way is to create another method for animating back and call it when the first animation is completed, like this:
-(void) moveDown{
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseIn animations:^{
int randomx = arc4random() % 295;
[redSquare setCenter:CGPointMake(randomx,435)];
} completion:^(BOOL finished) {
// First animation completed
[self moveBack];
}];
}
-(void) moveBack{
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseIn animations:^{
[redSquare setCenter:CGPointMake(redSquare.frame.origin.x,25)];
} completion:^(BOOL finished) {
// Second animation completed
}];
}

Resources