"Glitch" during UIView Intro CAAnimation - ios

I'm trying to add an Animation to a UIView. The objective of the animation is to "animate" the View appearing on screen (instead of just appearing there).
The animation is all size scaling: start from 5%, go up to 120% and then very quickly back to 100% of the regular scale.
My issue is that the full scale UIView appears very quickly, before the animation starts.
Here's the code:
UIView * myView = [[UIView alloc] initWithFrame:someFrame];
[self.view addSubview:myView];
[self initialAnimationFor:myView];
-(void) initialAnimationFor:(UIView*)pView {
const CFTimeInterval firstDuration = 0.75f;
const CFTimeInterval secondDuration = 0.025f;
const float initialValue = 0.05f;
const float middleValue = 1.20f;
CABasicAnimation * firstAnimation = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
firstAnimation.duration = firstDuration;
firstAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
firstAnimation.fromValue = [NSNumber numberWithFloat:initialValue];
firstAnimation.toValue = [NSNumber numberWithFloat:middleValue];
CABasicAnimation * secondAnimation = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
secondAnimation.duration = secondDuration;
secondAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
secondAnimation.fromValue = [NSNumber numberWithFloat:middleValue];
secondAnimation.toValue = [NSNumber numberWithFloat:1.0f];
CAAnimationGroup *animationGroup = [CAAnimationGroup new];
animationGroup.duration = firstDuration + secondDuration;
animationGroup.animations = #[firstAnimation, secondAnimation];
[pView.layer addAnimation:animationGroup forKey:nil];
}
Any ideas? Thanks!

I would do a different technique and use chained UIView block animations, like this:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(40, 40, 200, 200)];
myView.backgroundColor = [UIColor redColor];
[self initialAnimationFor:myView];
}
- (void)initialAnimationFor:(UIView*)pView {
pView.transform = CGAffineTransformMakeScale(0.05f, 0.05f);
if (pView.superview == nil) {
[self.view addSubview:pView];
}
[UIView
animateWithDuration:0.75f
animations:^{
pView.transform = CGAffineTransformMakeScale(1.20f, 1.20f);
}
completion:^(BOOL finished) {
[UIView
animateWithDuration:0.25f // <-- Your old value of 0.025f makes the animation VERY quick
animations:^{
pView.transform = CGAffineTransformIdentity;
}
];
}
];
}
With this setup, you get the "grow to slightly larger than 100% and then 'settle' to 100%" effect.
Is this a workable solution?

Related

How to change the rectangle shape to a circle shape with animation

I have a label:
self.logInLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 300, 100)];
self.logInLabel.backgroundColor = [UIColor clearColor];
self.logInLabel.backgroundColor = Color_Circle_Outer;
self.logInLabel.textColor = Color_Circle_Outer;
self.logInLabel.textAlignment = NSTextAlignmentCenter;
self.logInLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.logInLabel.numberOfLines = 1;
self.logInLabel.font = [UIFont boldSystemFontOfSize:12*IPAD];
self.logInLabel.text = #"Log In";
[self addSubview:self.logInLabel];
self.logInLabel.layer.cornerRadius = self.frame.size.height/2.0;
self.logInLabel.layer.borderColor = Color_Circle_Outer.CGColor;
self.logInLabel.layer.borderWidth = 2*IPAD;
self.logInLabel.layer.masksToBounds = YES;
I want to change this shape to a Circle. I have tried:
[UIView animateWithDuration:AnimationTime animations:^{
self.logInLabel.layer.bounds = CGRectMake(0, 0, self.frame.size.height, self.frame.size.height);
}];
But the shape changed immediately without animation, then the position change to center with animation. Then I tried with this:
[UIView animateWithDuration:AnimationTime animations:^{
self.logInLabel.bounds = CGRectMake(0, 0, self.logInLabel.frame.size.height, self.logInLabel.frame.size.height);
}];
I have very ugly animation effect.
I do not care if this view is a label, I just want to implement changing a rectangle shape to a circle shape with an animation.
Thank you.
It works only CABasicAnimation not the UIView animateWithDuration
UIView *logInLabel = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
logInLabel.backgroundColor = [UIColor blackColor];
logInLabel.layer.masksToBounds = YES;
[self.view addSubview:logInLabel];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"cornerRadius"];
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
animation.fromValue = [NSNumber numberWithFloat:0.0f];
animation.toValue = [NSNumber numberWithFloat:100.0f];
animation.duration = 5.0;
[logInLabel.layer addAnimation:animation forKey:#"cornerRadius"];
[logInLabel.layer setCornerRadius:0.0];
From your code remove the line :
self.logInLabel.layer.cornerRadius = self.logInLabel.frame.size.height / 2.0;
and put it in an animation block like this
You can set cornerRadius of your UILabel to get a circular view.
[UIView animateWithDuration:AnimationTime animations:^{
self.logInLabel.layer.cornerRadius = self.logInLabel.frame.size.height / 2.0f;
}];
However, the animation will not look very good and the final frame will not be an exact circle because the height and width of your UILabel are not in 1:1 proportion.
If you still don't get the animation try to check the value of AnimationTime variable.
Look that might help you
[UIView animateWithDuration:0.4 animations:^{
CGPoint center = self.logInLabel.center;
self.logInLabel.layer.cornerRadius = self.logInLabel.frame.size.height/2;
self.logInLabel.frame = CGRectMake(0, 0, self.logInLabel.frame.size.height, self.logInLabel.frame.size.height);
self.logInLabel.center = center;
}];

kCAMediaTimingFunctionEaseInEaseOut not affecting UIImageView

I have a cycle of images I am trying to fade from one to the other using kCAMediaTimingFunctionEaseInEaseOut so its not so abrupt. My UIImageView is receiving the objects from a MutableArray. Here is the code I am using to achieve the fade affect.
imageViewContainer = [UIView new];
imageViewContainer.frame = CGRectMake(0, 0, 320, 620);
imageViewContainer.backgroundColor = [UIColor clearColor];
[self.view1 addSubview:imageViewContainer];
for (int i = 0; i < [homescreenPictureArray count]; i++) {
homescreenPictureView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 50, 320, 620)];
homescreenPictureView.animationImages = homescreenPictureArray;
homescreenPictureView.animationDuration = 15;
[homescreenPictureView setAlpha:1.0f];
homescreenPictureView.contentMode = UIViewContentModeScaleAspectFill;
[imageViewContainer.layer addAnimation:pictureDisolve forKey:nil];
[imageViewContainer addSubview:homescreenPictureView];
pictureDisolve = [CATransition animation];
pictureDisolve.duration = 1.0f;
pictureDisolve.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
pictureDisolve.type = kCATransitionFade;
[homescreenPictureView.layer addAnimation:pictureDisolve forKey:#"imageViewContainer"];
[homescreenPictureView startAnimating];
I receive no errors when compiling yet its not affecting the images. Clarification on why its not working would be appreciated. Thanks in advance!
The transition type you're using is wrong. You need to use kCATransitionFade.
You need to specify the key value. for example #"subviews".
it defines, when and what will be transitioned.
pictureDisolve = [CATransition animation];
pictureDisolve.duration = 1.0f;
pictureDisolve.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
pictureDisolve.type = kCATransition;
[homescreenPictureView.layer addAnimation:pictureDisolve forKey:#"subviews"];
So I'm working on a different project now but I figured I would give a good example of the kCATransitionFade for anyone who views this in the future.
`-(void) fadeIn {
view1.image = background1;
view2.image = background2;
CATransition *fadeIn = [CATransition animation];
fadeIn.duration = 2.0f;
fadeIn.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
fadeIn.type = kCATransitionFade;
fadeIn.delegate = self;
[self.view.layer addAnimation:fadeIn forKey:nil];
view1.hidden = YES;
view2.hidden = NO;
NSLog(#"Image 1");
}
-(void) fadeOut {
view1.image = background1;
view2.image = background2;
CATransition *fadeIn = [CATransition animation];
fadeIn.duration = 2.0f;
fadeIn.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
fadeIn.type = kCATransitionFade;
fadeIn.delegate = self;
[self.view.layer addAnimation:fadeIn forKey:nil];
view1.hidden = NO;
view2.hidden = YES;
NSLog(#"Image 2");
}
`
For my project I left it for use as [self fadeIn] or [self fadeOut] but if you would like you can combine them into single function by calling
-(void) fadeFunction {
if (self.view == view1) {
[self fadeIn];
} else {
[self fadeOut];
}
}

Animating image on event

I have an image with circle inside circle approx 10 circles,each of different color i want to show them one by one on button click from center to outside and on another button click disappear one by one from outer to inner. Is this possible and how?
Please suggest
You can get help from below code i m not wrong and you are looking for radar style animation
#import "RadarAnimation.h"
#implementation RadarAnimation
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self SetUPAnimation];
// Initialization code
}
return self;
}
-(void)SetUPAnimation
{
[self AddRader];
double delayInSeconds = 1.5;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self AddRader];
});
}
-(void)AddRader
{
UIView *view = [[UIView alloc] init];
// view.backgroundColor = [UIColor blueColor];
view.frame=self.frame;
[self setWidth:[Helper currentWidth] ofView:view];
[self setHeight:[Helper currentWidth] ofView:view];
[self setXPossitionto:self.frame.size.width/2-view.frame.size.width/2 ofView:view];
[self setYPossitionto:self.frame.size.height/2-view.frame.size.height/2 ofView:view];
view.layer.cornerRadius = CGRectGetHeight(view.frame)/2;
view.tag=175751;
int kRingExpansionTime=6.0;
CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
scaleAnimation.duration = kRingExpansionTime;
scaleAnimation.repeatCount = HUGE_VAL;
scaleAnimation.autoreverses = YES;
scaleAnimation.fromValue = [NSNumber numberWithFloat:0.0];
scaleAnimation.toValue = [NSNumber numberWithFloat:1.8];
[view.layer addAnimation:scaleAnimation forKey:#"scale"];
// fade out the ring part way thru the animation
CABasicAnimation* alphaAnim = [CABasicAnimation animationWithKeyPath:#"opacity"];
alphaAnim.fromValue = [NSNumber numberWithFloat:0.3];
alphaAnim.toValue = [NSNumber numberWithFloat:0.1];
alphaAnim.beginTime = kRingExpansionTime * 0.7f; // start part way thru
alphaAnim.duration = kRingExpansionTime - alphaAnim.beginTime;
CAAnimationGroup* group = [CAAnimationGroup animation];
group.duration = kRingExpansionTime;
group.repeatCount = HUGE_VALF; // repeat forever
group.animations = [NSArray arrayWithObjects:scaleAnimation,alphaAnim, nil];
[view.layer addAnimation:group forKey:nil];
view.backgroundColor = [UIColor colorWithRed:0/255.0 green:135.0/255.0 blue:219.0/255.0 alpha:0.5];
view.alpha=0.4;
view.layer.borderColor = [UIColor colorWithRed:0/255.0 green:135.0/255.0 blue:255.0/255.0 alpha:1.0].CGColor;
view.layer.borderWidth = 2.0;
//view.center=_VwEmptyplaceholder.center;
//view.center=CGPointMake(_VwEmptyplaceholder.frame.size.width/2, _VwEmptyplaceholder.frame.size.height/2);
view.userInteractionEnabled=NO;
view.tag=175751;
//[self insertSubview:view belowSubview:btn];
}
-(void)setXPossitionto:(CGFloat)xpostion ofView:(UIView *)view
{
CGRect frame = view.frame;
frame.origin.x = xpostion;
view.frame=frame;
}
-(void)setYPossitionto:(CGFloat)ypostion ofView:(UIView *)view
{
CGRect frame = view.frame;
frame.origin.y = ypostion;
view.frame=frame;
}
-(void)setWidth:(CGFloat)Width ofView:(UIView *)view
{
CGRect frame = view.frame;
frame.size.width = Width;
view.frame=frame;
}
-(void)setHeight:(CGFloat)Height ofView:(UIView *)view
{
CGRect frame = view.frame;
frame.size.height = Height;
view.frame=frame;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end

CABasicAnimation back to its original position after it finish it's 1 cycle

Don't refer CABasicAnimation returns to the original position before the next animation and Objective-C - CABasicAnimation applying changes after animation? and CABasicAnimation rotate returns to original position
i have tried.
below code does,bottom->top->goes left->back to it’s original position.
bottom->top->goes left->back to its original position.
I need bottom->top->goes left.bottom->top->goes left so on…
-(void)addUpDownAnimationForButton:(UILabel*)label
{
CABasicAnimation * bottomAnimation ;
bottomAnimation =[CABasicAnimation animationWithKeyPath:#"transform.translation.y"];
[bottomAnimation setValue:#"animation1" forKey:#"id"];
bottomAnimation.delegate = self;
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:)];
bottomAnimation.duration = 2.0;
bottomAnimation.fromValue = [NSNumber numberWithFloat:13];
bottomAnimation.toValue = [NSNumber numberWithFloat:-7];
bottomAnimation.repeatCount = 0;
bottomAnimation.fillMode = kCAFillModeForwards;
bottomAnimation.removedOnCompletion = NO;
[btnSpecialForListing.titleLabel.layer addAnimation:bottomAnimation forKey:#"transform.translation.y"];
}
- (void)animationDidStop:(CAAnimation *)theAnimation2 finished:(BOOL)flag
{
if([[theAnimation2 valueForKey:#"id"] isEqual:#"animation1"]) {
CABasicAnimation *moveAnimation;
moveAnimation=[CABasicAnimation animationWithKeyPath:#"transform.translation.x"];
moveAnimation.duration=3.5;
moveAnimation.repeatCount=0;
moveAnimation.autoreverses=NO;
moveAnimation.fromValue=[NSNumber numberWithFloat:0];
moveAnimation.toValue=[NSNumber numberWithFloat:-400];
moveAnimation.removedOnCompletion = NO;
moveAnimation.fillMode = kCAFillModeRemoved;
[btnSpecialForListing.titleLabel.layer addAnimation:moveAnimation forKey:#"transform.translation.x"];
}
}
Any help would be greatly appreciated.
Thanks !!
Have you tried this?
moveAnimation.fillMode = kCAFillModeForwards;
moveAnimation.removedOnCompletion = NO;
EDIT
As far as I can see you can also use animateWithDuration which has a completion block.
Example would be:
CGRect rect = btnSpecialForListing.titleLabel.frame;
[UIView animateWithDuration:2.0 animations:^{
rect.origin.y = -7;
btnSpecialForListing.titleLabel.frame = rect;
} completion:^(BOOL finished){
[UIView animateWithDuration:3.5 animation:^{
rect.origin.x = -400;
btnSpecialForListing.titleLabel.frame = rect;
}];
}];
Swift 4.2/5:
moveAnimation.fillMode = .forwards
moveAnimation.isRemovedOnCompletion = false

iOS animation with duration and autoreverse

I am animating an UIImageView with the UIView block API. My animation fades the UIImageView In and Out continuously. How can I animate this only for a specific time duration ?
I have put up this piece of code
float tempDuration = 5.0;
[UIView animateWithDuration:tempDuration
delay:0
options:UIViewAnimationOptionAutoreverse | UIViewAnimationOptionAllowUserInteraction
animations:^{
_imageView.alpha = 1;
}
completion:nil];
First of all allow me to introduce an article that is awesome to understand some features of the animations:
Controlling Animation Timming
In this article you have a part that shows what you want.
You want something like this:
Therefore you can configure that in the following way:
-(void) animateImageView:(UIImageView*) imageView
withDuration:(int) duration
withRepeatCount: (int) repeatCount {
CABasicAnimation *opacityAnim = [CABasicAnimation animationWithKeyPath:#"opacity"];
opacityAnim.fromValue = #1.0;
opacityAnim.toValue = #0.0;
opacityAnim.autoreverses = YES;
opacityAnim.duration = duration/2.0/repeatCount;
opacityAnim.removedOnCompletion = YES;
opacityAnim.repeatCount = repeatCount;
[imageView.layer addAnimation:opacityAnim forKey:nil];
}
This way you guarantee that your animation will always be 5 seconds and you can tune in the number of repetitions.
Maybe you could try CABasicAnimation instead if [UIView animateWithDiration: ... ]
it should be something like this:
CABasicAnimation *opacityAnim = [CABasicAnimation animationWithKeyPath:#"opacity"];
opacityAnim.fromValue = [NSNumber numberWithFloat:1.0];
opacityAnim.toValue = [NSNumber numberWithFloat:0.0];
opacityAnim.autoreverses = YES;
opacityAnim.duration = duration;
opacityAnim.removedOnCompletion = YES;
opacityAnim.repeatCount = 5;
[imageView.layer addAnimation:opacityAnim forKey:nil];
You can do the following changes to do your work.
- (void)animateImageView{
static int animcount = 1;
float tempDuration = 1.0;
[UIView animateWithDuration:tempDuration
delay:0
options: UIViewAnimationOptionAutoreverse
animations:^{
self.imgView.alpha = 1;
}
completion:^(BOOL finished) {
if(finished && animcount<5){
animcount+=1;
[self animateImageView];
}
else if (finished && animcount==5){
[self.imgView.layer removeAllAnimations];
}
}];
}

Resources