I am trying to build an introduction to my app with UILabels fading in and out. I have two labels. I want the first one to fade in, stay on the screen for 4 seconds. Then second label should fade in and stay on the screen for 4 seconds. Then it should fade out both the labels.
I have the following code but it does not do anything since it goes straight to the final state. I have the following method in viewDidAppear(). What am I doing wrong?
-(void) animateLabels
{
[UIView beginAnimations:#"First Label Display" context:nil];
[UIView setAnimationDelay:4.0];
firstLabel.alpha = 1;
[UIView commitAnimations];
[UIView beginAnimations:#"Second Label Display" context:nil];
[UIView setAnimationDelay:6.0];
secondLabel.alpha = 1;
[UILabel commitAnimations];
[UIView beginAnimations:#"Hide Labels" context:nil];
[UIView setAnimationDelay:10.0];
secondLabel.alpha = 0;
firstLabel.alpha=0;
[UILabel commitAnimations];
}
Use block based animation & chain your animations together. So there are 3 steps. label1 fadesIn, Label2 fadesIn, finally Label3 fadesIn. I have written the code below for fading in label1 & label2. Fading out is simple. I think you can fill in the rest. Its straight-forward from here...
Try this -
[UIView animateWithDuration:1.0
delay:4
options:UIViewAnimationOptionCurveLinear | UIViewAnimationOptionAllowUserInteraction
animations:^(void)
{
[firstLabel setAlpha:1.0];
}
completion:^(BOOL finished)
{
if(finished)
{
[UIView animateWithDuration:1.0
delay:4.0
options:UIViewAnimationOptionCurveLinear | UIViewAnimationOptionAllowUserInteraction
animations:^(void)
{
[secondLabel setAlpha:1.0];
}
completion:^(BOOL finished)
{
if(finished)
{
//put another block her to hide both the labels.
}
}];
}
}];
I suggest rewriting this using blocks. First animateWithDuration:animations:completion: and then nested animateWithDuration:delay:options:animations:completion:. It's far more flexible, and there's no need to run on pre-blocks systems these days.
Also, your first animation as written wouldn't trigger for 4 seconds.
Here is a solution in swift 4+
UIView.animate(withDuration: 1.0, delay: 4, options: [.curveLinear, .allowUserInteraction], animations: {
firstLabel.alpha = 1.0
}) { finished in
if finished {
UIView.animate(withDuration: 1.0, delay: 4.0, options: [.curveLinear, .allowUserInteraction], animations: {
secondLabel.alpha = 1.0
}) { finished in
if finished {
//put another block her to hide both the labels.
}
}
}
}
Related
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
}
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 want to create a menu view which hides and unhides on button press. Now I managed to do it to the parent view but the buttons which are subview of the menuview are not scaling accordingly what i need to do? Here's the code!
menuInitFrame=menuView.frame;
newFrame=CGRectMake(320, 0, 0, 0);
Storing the initial state and new state;
if (menuView.hidden==NO) {
[UIView animateWithDuration:0.5
delay: 0.5
options: UIViewAnimationOptionCurveEaseIn
animations:^{
menuView.frame = newFrame; // move
}
completion:^(BOOL finished)
{
menuView.hidden=YES;
}];
}
else if(menuView.hidden==YES)
{
menuView.hidden=NO;
[UIView animateWithDuration:0.5
delay: 0.5
options: UIViewAnimationOptionCurveEaseIn
animations:^{
menuView.frame = menuInitFrame;
}
completion:^(BOOL finished)
{
//menuViewStatus=NO;
}];
}
Since you're using auto-layout you need to call layoutIfNeeded to recalculate frames of all subviews inside your menuView.
So inside your animation block add the following line:
menuView.frame = menuInitFrame;
[menuView layoutIfNeeded];
Consider this basic view animation. It will scale a view down to nothing over the course of 1 second:
[UIView animateWithDuration: 1.0
delay: 0.0
options: UIViewAnimationCurveEaseIn
animations:^{
vw.transform = CGAffineTransformMakeScale(0.0, 0.0);
}
completion:^(BOOL finished) {
if (finished) {
vw.transform = CGAffineTransformIdentity;
}
}
];
What I'd like to do is use this same animation on many different views at different times throughout my app. To do this, I can easily put it in a method, pass in the view I want to zoom. No problem.
The challenge is that I may need to do different things at the completion of the animation depending on the situation. For example, I may want to remove the view from the SuperView in one case, and I may want to move the view to a new location (for zooming in later) in another case.
In a nutshell: How can I notify the caller of my method when the animation completes?
completion:^(BOOL finished) {
if (finished) {
vw.transform = CGAffineTransformIdentity;
// Do something unique here
}
}
You can just pass in the completion block itself as well:
- (void)animateView:(UIView *)v completion:(void ^(BOOL))ch
{
[UIView animateWithDuration: 1.0
delay: 0.0
options: UIViewAnimationCurveEaseIn
animations:^{
v.transform = CGAffineTransformMakeScale(0.0, 0.0);
}
completion:ch
];
}
Then call it like
[self animateView:someView completion:^(BOOL flag) {
// do stuff here
}];