In objective-c, I want to add fade in and fade out animation to a UIView. I want to do the fade-out and fade-in animation continuously. To illustrate it, what effect I want to have is as following:
fade out - fade in - fade out - fade in - ...
What I'm trying is as following:
-(void)fadeOutIn:(UIView *)view duration:(NSTimeInterval)duration
{
static CGFloat alpha = 1.0;
[UIView animateWithDuration:duration
delay:0.0
options: UIViewAnimationOptionRepeat| UIViewAnimationOptionCurveEaseInOut
animations:^{
alpha = abs((int)(alpha - 1.0));
view.alpha = alpha;
}
completion:^(BOOL finished){
}];
}
I also tried following:
-(void)fadeOutIn:(UIView *)view duration:(NSTimeInterval)duration
{
[UIView animateWithDuration:duration
delay:0.0
options: UIViewAnimationOptionRepeat| UIViewAnimationOptionCurveEaseInOut
animations:^{
view.alpha = 0.0;
}
completion:^(BOOL finished){
[UIView animateWithDuration:duration
delay:0.0
options: UIViewAnimationOptionRepeat|UIViewAnimationOptionCurveEaseInOut
animations:^{
view.alpha = 1.0;
}
completion:^(BOOL finished){
}];
}];
}
But the issue is they worked all the same, i.e., the UIView will fade out properly and SUDDENLY show up(not fade in), then fade out again...
Seems the fade in animation not work at all. Does anybody know what's wrong of my code please? Any suggestion will be highly appreciated.
Try this
[UIView animateKeyframesWithDuration:1 delay:0 options:UIViewAnimationOptionRepeat|UIViewAnimationOptionAutoreverse|UIViewAnimationCurveEaseInOut animations:^{
self.customIV.alpha = 0;
} completion:^(BOOL finished) {
}];
Here's this, Vigor, this does work, but I had to modify the code, this is somewhat dangerous code, due to it's constant recursiion, but you'll get the point:
-(void)fadeOutIn
{
[UIView animateWithDuration:1
delay:0.0
options: UIViewAnimationOptionCurveEaseInOut
animations:^{
[[self contentView] emailField].alpha = 0.0;
}
completion:^(BOOL finished){
[UIView animateWithDuration:1
delay:0.0
options: UIViewAnimationOptionCurveEaseInOut
animations:^{
[[self contentView] emailField].alpha = 1.0;
}
completion:^(BOOL finished){
[self fadeOutIn];
}];
}];
}
I would really rethink how this works, I used it on a button in my view and it will recurse constanly, until the view is removed from the superview. I had to hardcode the button in the code.
[UIView animateWithDuration:duration
delay:0.0
options: UIViewAnimationOptionRepeat| UIViewAnimationOptionAutoreverse|UIViewAnimationOptionCurveEaseInOut
animations:^{
view.alpha = 0.0;
}
completion:nil];
Just call this once
Try this....
YourView.alpha = 1;// set the initial value of alpha
[UIView animateWithDuration:1 delay:0
options: UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeat
animations:^{
YourView.alpha = 0; // set the max value of alpha
} completion:nil];
This solution is for Swift 3,4 and 5
UIView.animateKeyframes(withDuration: 1, delay: 0, options: [UIView.KeyframeAnimationOptions(rawValue: UIView.AnimationOptions.repeat.rawValue), UIView.KeyframeAnimationOptions(rawValue: UIView.KeyframeAnimationOptions.RawValue(UIView.AnimationCurve.easeInOut.rawValue)), UIView.KeyframeAnimationOptions(rawValue: UIView.AnimationOptions.autoreverse.rawValue)] , animations: {
self.logoCenterImageView.alpha = 0
}) { finished in
}
Related
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];
}];
Actually i am using RESlider in my app. In the menu table view there is a profile image and aside to it there is a notification label. Now i want is that when the user presses the hamburger menu the notification label(orange label with 999 number) should animate from a tiny dot to its original size. How to achieve this??
Put this in viewDidAppear
-(void)viewDidAppear:(BOOL)animated{
self.label.transform = CGAffineTransformMakeScale(0.01, 0.01);
[UIView animateWithDuration:0.5 animations:^{
self.label.transform = CGAffineTransformIdentity;
} completion:^(BOOL finished) {
}];
}
myTextLabel.transform = CGAffineTransformMakeScale(0.3, 0.3);
[UIView animateWithDuration:2.0
delay: 0.1
options: UIViewAnimationOptionBeginFromCurrentState
animations:^{
myTextLabel.transform = CGAffineTransformMakeScale(1.5, 1.5); //grow
}
completion:^(BOOL finished){
myTextLabel.transform = CGAffineTransformMakeScale(1, 1);
}];
Change the transform scale of your label, like this :
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeat | UIViewAnimationOptionCurveEaseInOut
animations:^{
timerLabel.transform = CGAffineTransformScale(timerLabel.transform, 0.7, 0.7);
}
completion:nil];
I want to create button which has "elastic" press down animation.
Animation description:
On press:
scale it on 80% in 0.1s
scale it on 90% in 0.1s // when pressed it should stay at 90% scale
On release:
scale it on 110% in 0.1s
scale it on 100% in 0.1s // when released - scale should finish at 100%
I tried to implement this with code:
-(void) pressedAnimation {
[UIView animateWithDuration:kAnimationTime
delay:0.0
options: UIViewAnimationOptionBeginFromCurrentState
animations:^{
self.transform = CGAffineTransformMakeScale(.8f, .8f);
}completion:^(BOOL finished){
if (finished) {
[UIView animateWithDuration:kAnimationTime
delay:0.0
options: UIViewAnimationOptionBeginFromCurrentState
animations:^{
self.transform = CGAffineTransformMakeScale(.9f, .9f);
}completion:^(BOOL finished){
}];
}
}];
}
-(void) releasedAnimation {
[UIView animateWithDuration:kAnimationTime
delay:0.0
options: UIViewAnimationOptionBeginFromCurrentState
animations:^{
self.transform = CGAffineTransformMakeScale(1.1f, 1.1f);
}completion:^(BOOL finished){
if (finished) {
[self.layer removeAllAnimations];
[UIView animateWithDuration:kAnimationTime
delay:0.0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
self.transform = CGAffineTransformMakeScale(1.0f, 1.0f);
}completion:^(BOOL finished){
}];
}
}];
}
Animation works as expected only if "releasedAnimation" is called when "pressedAnimation" is already completed. Else I got very strange effects.
I tried to use [self.layer removeAllAnimations] in both methods but it doesn't work as expected. It seems like UIViewAnimationOptionBeginFromCurrentState doesn't work. What am I doing wrong? Is there a better way to create such an animation?
You could abstract this behavior out to a utility class. Try something like this:
For the .h:
+(void)buttonBobble:(UIButton *)button actionWhenDone:(void(^)(BOOL))action;
For .m:
+(void)buttonBobble:(UIButton *)button actionWhenDone:(void (^)(BOOL))action
{
button.transform = CGAffineTransformMakeScale(0.8f, 0.8f);
[UIView animateWithDuration:0.5f animations:^{
button.transform = CGAffineTransformMakeScale(1.0f, 1.0f);
}completion:action];
}
Of course, you may have to tweak this for the right look you want. You'll also want to add the UIViewAnimationOptionBeginFromCurrentState if you want it to pick up right where the button is at.
I am trying to chain a set of UIView animateWithDuration: using the flag UIViewAnimationOptionRepeat
The animation steps I am trying to repeat are:
Animate a UIView 100 pixels to the left
Fade the UIView out (opacity '0')
While faded out (invisible), move it back to the original position (100 px to the right)
Fade the UIView back in (set opacity to '1')
Repeat the animation using flag UIViewAnimationOptionRepeat
I am not able to repeat the whole chain of animations - and only able to repeat the top most animation.
The code I have tried is this:
[UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionRepeat animations:^{
self.handImageView.frame = CGRectMoveByXPixels(self.handImageView.frame, -100);
[UIView animateWithDuration:0.5 delay:1 options:0 animations:^{
self.handImageView.alpha = 0;
} completion:^(BOOL finished) {
self.handImageView.frame = CGRectMoveByXPixels(self.handImageView.frame, 100);
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
self.handImageView.alpha = 1;
} completion:^(BOOL finished) {
}];
}];
} completion:^(BOOL finished) {
}];
The problem is that an animation that uses UIViewAnimationOptionRepeat never finishes and therefore never calls the completion block. However, you can repeat the animations using the performSelector method, as shown in the code below.
- (void)repeatingAnimationForView:(UIView *)view
{
[UIView animateWithDuration:1 delay:0 options:0
animations:^{ view.frame = CGRectMoveByXPixels(view.frame, -100); }
completion:^(BOOL finished) { if ( finished ) {
[UIView animateWithDuration:0.5 delay:0 options:0
animations:^{ view.alpha = 0; }
completion:^(BOOL finished) { if ( finished ) {
view.frame = CGRectMoveByXPixels(view.frame, 100);
[UIView animateWithDuration:0.5 delay:0 options:0
animations:^{ view.alpha = 1; }
completion:^(BOOL finished) { if ( finished ) {
if ( self.enableRepeatingAnimation )
[self performSelector:#selector(repeatingAnimationForView:) withObject:view afterDelay:0];
}}]; }}]; }}];
}
- (void)stopRepeatingAnimationForView:(UIView *)view
{
self.enableRepeatingAnimation = NO;
[view.layer removeAllAnimations];
view.frame = CGRectMake( 100, 137, 80, 50 );
view.alpha = 1;
}
- (void)startRepeatingAnimationForView:(UIView *)view
{
self.enableRepeatingAnimation = YES;
[self repeatingAnimationForView:view];
}
To stop the animations immediately, call the stopRepeatingAnimationForView method as shown above. To stop the animations at the end of a cycle, simply set self.enableRepeatingAnimation to NO.
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];
}];
}