I am having diffuculties about bouncies animation effect , whenever i swipe down, The two UI elements swipe down , 1st is container ( which holds UIPickerView ) and it changes coordinate(x,y) and w/h value, second UI is just for pull on/off and I am only applying it's coordinates. I am doing it with FacebookPOP Framework and i also applied bounce effect. First pulling down , 2 UI has a trailing space while keeping in bounce effect. Without change or refresh view controller, second / third's swipe down action occurs as i expected .
My code while swipe down / up looks like that :
if(sender.direction == UISwipeGestureRecognizerDirectionDown)
{
isDown = YES;
POPSpringAnimation *bounceForControlView = [POPSpringAnimation animation];
bounceForControlView.property = [POPAnimatableProperty propertyWithName:kPOPViewFrame];
bounceForControlView.toValue=[NSValue valueWithCGRect:CGRectMake(0, 241, 320, 42)];
bounceForControlView.springBounciness = 15;
bounceForControlView.springSpeed = 10;
[controlView pop_addAnimation:bounceForControlView forKey:#"bounceForControlView"];
POPSpringAnimation *bounceForPickerView = [POPSpringAnimation animation];
bounceForPickerView.property = [POPAnimatableProperty propertyWithName:kPOPViewFrame];
bounceForPickerView.toValue=[NSValue valueWithCGRect:CGRectMake(0, 64, 320, 177)];
bounceForPickerView.springBounciness = 15;
bounceForPickerView.springSpeed = 10;
[swipeView pop_addAnimation:bounceForPickerView forKey:#"bounceForPickerView"];
[UIView animateWithDuration:0.7 animations:^() {
[pullUPImage setAlpha:1.0];
[self.pullImage setAlpha:0.0];
}];
[UIView animateWithDuration:0.7 animations:^() {
[myPicker setHidden:NO];
}];
}
if(sender.direction == UISwipeGestureRecognizerDirectionUp)
{
isDown = NO;
[myPicker setHidden:YES];
popAnimation = [POPSpringAnimation animation];
popAnimation.property = [POPAnimatableProperty propertyWithName:kPOPViewFrame];
popAnimation.toValue=[NSValue valueWithCGRect:CGRectMake(0, 64, 320, 0)];
popAnimation.springBounciness = 5;
popAnimation.springSpeed = 5;
[swipeView pop_addAnimation:popAnimation forKey:#"slide"];
popAnimation = [POPSpringAnimation animation];
popAnimation.property = [POPAnimatableProperty propertyWithName:kPOPViewFrame];
popAnimation.toValue=[NSValue valueWithCGRect:CGRectMake(0, 64, 320, 42)];
popAnimation.springBounciness = 5;
popAnimation.springSpeed = 5;
[controlView pop_addAnimation:popAnimation forKey:#"slide"];
[UIView animateWithDuration:0.5 animations:^() {
[pullUPImage setAlpha:0.0];
[self.pullImage setAlpha:1.0];
}];
}
This is how animation works in realtime :
Related
I have a situation where I have to rotate the image like a coin. I am doing as follows.
CATransition* transition = [CATransition animation];
transition.startProgress = 0;
transition.endProgress = 1.0;
transition.type = #"flip";
transition.subtype = #"fromRight";
transition.duration = 1.0;
transition.repeatCount = 15;
[rotateimageView.layer addAnimation:transition forKey:#"transition"];
It is rotating the image but it is not completely rotating it Please check the video.
https://www.dropbox.com/s/x4t2aqyscgecqfb/animationVideo.mov?dl=0
It looks like rotating but the right pointing arrow never points left. I want it to point left and right as a complete coin animation.
Check out the following article in which I explained how to rotate a banner. Maybe you can apply the same techniques in your application.
http://highoncoding.com/Articles/876_Creating_a_Flipping_Tweets_View.aspx
-
(void) updateFlippingView:(NSTimer *) timer
{
if(index == ([tweets count] -1))
{
index = 0;
}
UILabel *messageLabel = (UILabel *) [flippingView viewWithTag:MESSAGE_LABEL_TAG];
[UIView animateWithDuration:1.0 animations:^{
[UIView animateWithDuration:2.0 animations:^{
messageLabel.alpha = 0.0;
} completion:^(BOOL finished) {
[UIView animateWithDuration:1.0 animations:^{
messageLabel.alpha = 1.0;
messageLabel.text = [tweets objectAtIndex:index];
}];
}];
flippingView.layer.transform = CATransform3DMakeRotation(rotationIndex *M_PI, 1.0, 0.0, 0.0);
for(UIView *subView in flippingView.subviews)
{
subView.layer.transform = CATransform3DMakeRotation(rotationIndex *M_PI, 1.0, 0.0, 0.0);
}
}
completion:^(BOOL finished) {
rotationIndex = rotationIndex == 1 ? 2 :1;
}];
index++;
}
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?
Here is a transition code I have for Showing ViewB from ViewA
CGPoint c = thepoint;
CGFloat tx = c.x - floorf(theview.center.x) + 10;
CGFloat ty = c.y - floorf(theview.center.y) + 100;
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
// Transforms
CGAffineTransform t = CGAffineTransformMakeTranslation(tx, ty);
t = CGAffineTransformScale(t, 0.1, 0.1);
theview.transform = t;
theview.layer.masksToBounds = YES;
[theview setTransform:CGAffineTransformIdentity];
}
completion:^(BOOL finished) {
}];
Now that the transition went very smooth without issues.
When in my ViewB, I had a text box with default focus. (In viewDidAppear)
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:NO];
[self performSelector:#selector(focusCommentText) withObject:nil afterDelay:0.5];
}
- (void) focusCommentText {
[self focusTextbox:commentText];
}
- (void) focusTextbox : (UITextView *) textView{
#try {
[ textView becomeFirstResponder];
}
#catch (NSException *exception) {
}
}
The Transition and the Keyboard coming up.. happens at same time.. And it is slightly awkward now. Can some one help me out here please?
What I would do is not call [textView becomeFirstResponder] until after the transition has completed.
EDIT: The killer was actually the background color of my view was transparent with alpha 0.8. Once I made it opaque (alpha = 1.0), the animation was smooth!!
I modified my code to make the focus of text box only after completion of the animation.
CGPoint c = thepoint;
CGFloat tx = c.x - floorf(theview.center.x) + 10;
CGFloat ty = c.y - floorf(theview.center.y) + 100;
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
// Transforms
CGAffineTransform t = CGAffineTransformMakeTranslation(tx, ty);
t = CGAffineTransformScale(t, 0.1, 0.1);
theview.transform = t;
theview.layer.masksToBounds = YES;
[theview setTransform:CGAffineTransformIdentity];
}
completion:^(BOOL finished) {
if( theview.tag == 1000) {
if(myVC != nil)
[myVC focusCommentText]; /// Here is where I set focus
}
}];
When CATransition is used, it is the delegate animationDidStop I have to choose.
CATransition *transition = [CATransition animation];
transition.duration = 0.4;
transition.type = kCATransitionFromRight; //choose your animation
transition.subtype = kCATransitionFade;
transition.delegate = self; //Setting Delegate as Self
[self.view.layer addAnimation:transition forKey:nil];
[self.view addSubview:myVC.view];
#pragma mark - CATransition Delegate
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
{
if(myVC != nil) {
[myVC focusCommentText];
}
}
I have a problem when playing multiple UIView animation blocks.
What I have is a game with a lot of buttons, when you press a button it spawns an UILabel which animates to the top of the screen where is gets "added" to the total point amount, this is done by using 3 nested blocks.
This works well an lets me spawn as many point labels as possible with animations on them.
//setup the label
UILabel *pointIndicator = [[UILabel alloc]initWithFrame:CGRectMake(button.button.frame.origin.x, button.button.frame.origin.y, 60, 30)];
pointIndicator.backgroundColor = [UIColor clearColor];
pointIndicator.font = [UIFont boldSystemFontOfSize:25];
pointIndicator.alpha = 0;
pointIndicator.layer.shadowOffset = CGSizeMake(1.0f, 1.0f);
pointIndicator.layer.shadowOpacity = 0.6;
pointIndicator.layer.shadowRadius = 1;
[pointIndicators addObject:pointIndicator];
[self.view addSubview:pointIndicator];
CGPoint scoreLabelPosition = [self.view convertPoint:self.totalScoreLabel.frame.origin fromView:self.totalScoreLabel.superview];
CGSize scoreLabelSize = [self.totalScoreLabel.text sizeWithFont:self.totalScoreLabel.font];
[UILabel animateWithDuration:0.3 delay:0 options:UIViewAnimationCurveEaseIn animations:^{
//Make label appear and move it above button
CGRect frame = pointIndicator.frame;
frame.origin.y -= 30;
pointIndicator.frame = frame;
pointIndicator.alpha = 1;
}completion:^(BOOL finished){
[UILabel animateWithDuration:0.4 delay:0 options:UIViewAnimationCurveEaseInOut animations:^{
//Move the label next to the score label
NSInteger YPosition = 0;
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad){
YPosition = 15;
}else{
YPosition = 2;
}
CGRect frame = pointIndicator.frame;
frame.origin.x = scoreLabelPosition.x + self.totalScoreLabel.frame.size.width/2 + scoreLabelSize.width/2 + 5;
frame.origin.y = scoreLabelPosition.y - self.totalScoreLabel.frame.size.height/2 + YPosition;
pointIndicator.frame = frame;
}completion:^(BOOL finished){
[UILabel animateWithDuration:0.5 animations:^{
pointIndicator.alpha = 0;
}completion:^(BOOL finished){
//Animate point label to increase a bit in size
CABasicAnimation *pointAnim = [CABasicAnimation animationWithKeyPath:#"transform"];
pointAnim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
pointAnim.duration = 0.1;
pointAnim.repeatCount = 1;
pointAnim.autoreverses = YES;
pointAnim.removedOnCompletion = YES;
pointAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.5, 1.5, 1.0)];
[self.totalScoreLabel.layer addAnimation:pointAnim forKey:nil];
[pointIndicator removeFromSuperview];
[pointIndicators removeObject:pointIndicator];
}];
}];
}];
However, when the game is ended all the buttons animate out of the screen and an image view grows in size out of the middle, each are using 1 animation block.
The problem is that if an UILabel is animating across the screen at the same time as the game ends it cancels the button animation AND the growing image animation. If no UILabels are spawned everything plays as it should. I tried to cancel and remove all the point labels before playing the other animations, but with no luck. It only seems to work if all the previous animations have been completed normally in advance. This is how I remove them:
for(UIView *pointView in pointIndicators){
[pointView.layer removeAllAnimations];
[pointView removeFromSuperview];
}
[pointIndicators removeAllObjects];
[self.totalScoreLabel.layer removeAllAnimations];
all the views which are animated are subviews of the same UIView. I noticed that if I make the point labels subviews of the buttons all the animations can play at the same time.
I cant seem to figure out this behavior, is there some sort of conflict between the animations?
I'm doing a simple animation of UIView height so that it reveals.
By default it seems to be revealing from top to bottom, and I want it to reveal bottom to top.
I have the UIView anchored to the bottom of the screen.
I'm sure it something simple i'm missing..... any tips?
Thanks
I really think the simplest way to accomplish this would be to animate BOTH the height and the y properties of the view. If they happen along the same curve, it should look completely seamless to the user. As you are animating the height to 0, also animate the y component to the original y + the original height.
UIView *view = ...;
float originalY = view.frame.origin.y;
float originalH = view.bounds.size.height;
[UIView animateWithDuration:1.2f delay:1.0f options:UIViewAnimationCurveEaseInOut animations:^{
view.frame = CGRectMake(view.frame.origin.x, (originalY + originalH), view.bounds.size.width, 0);
}completion:^(BOOL finished) {
NSLog(#"Animation is complete");
}];
I believe this would give the look and feel of a collapsing view. I haven't tried this out in code, but I see no reason why it wouldn't be possible like this.
hide under bottom
[self animateViewHeight:myView withAnimationType:kCATransitionFromBottom];
for reverse animation
[self animateViewHeight:myView withAnimationType:kCATransitionFromTop];
...
- (void)animateViewHeight:(UIView*)animateView withAnimationType:(NSString*)animType {
CATransition *animation = [CATransition animation];
[animation setType:kCATransitionPush];
[animation setSubtype:animType];
[animation setDuration:0.5];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[[animateView layer] addAnimation:animation forKey:kCATransition];
animateView.hidden = !animateView.hidden;
}
Like a dog with a bone I figured this out....
Instead of animating the frame height, I applied a transform to the view and set the anchor point of the layer.
//set the anchor point to the bottom of the view
[self setAnchorPoint:CGPointMake(0.5, 1.0) forView:hostView];
//Scale the height to close to zero
hostView.transform = CGAffineTransformMakeScale(1, 0.00001);
If I put 0 as the y scale, the view behaves weird.... at the end of the animation i just set it to hidden.
On the way back up I just use the Identity Transform (reset it)
hostView.transform = CGAffineTransformIdentity;
Note that changing my anchor point shifted the position of my view. See this post for the setAnchorPoint method which normalises the view after setting the anchorPoint
Changing my CALayer's anchorPoint moves the view
Instead you could try putting it in a view with clipsToBounds = YES and then animate it from the bottom to the middle of the view, like so:
viewToAnimate.frame = CGRectMake(viewToAnimate.frame.origin.x,
viewToAnimate.superview.frame.size.height,
viewToAnimate.frame.size.width,
viewToAnimate.frame.size.height);
[UIView animateWithDuration:0.5 animations:^{
viewToAnimate.center = viewToAnimate.superview.center;
}];
This way, you don't have to set the height to 0, and it solves any problems with autoresizing within the view.
As requested, this is the code that I'm using... I'm using a CAKeyFrameAnimation, which may be a bit more than what you're looking for. It would probably work the same with a CABasicAnimation, I'm just showing you this code because I already have it written.
-(id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
springLayer = [[CALayer alloc] init];
springLayer.backgroundColor = [UIColor redColor].CGColor;
springLayer.anchorPoint = CGPointMake(0, 1);
springLayer.frame = CGRectMake(125, 285, 100, 115);
[springLayer setNeedsDisplay];
[self.layer addSublayer:springLayer];
[self test];
}
return self;
}
-(void)test {
CAKeyframeAnimation *heightAnim = [[CAKeyframeAnimation alloc] init];
heightAnim.duration = 3;
heightAnim.removedOnCompletion = NO;
heightAnim.fillMode = kCAFillModeForwards;
heightAnim.beginTime = CACurrentMediaTime() + 0.25;
NSMutableArray *v = [[NSMutableArray alloc] init];
NSMutableArray *t = [[NSMutableArray alloc] init];
float dest = 250;
float difference = 135;
while (difference > 1.0) {
[v addObject:[NSNumber numberWithFloat:dest-difference]];
[t addObject:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];
difference *= 0.7;
[v addObject:[NSNumber numberWithFloat:dest+difference]];
[t addObject:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];
difference *= 0.7;
}
heightAnim.values = v;
heightAnim.timingFunctions = t;
[springLayer addAnimation:heightAnim forKey:#"bounds.size.height"];
}
one way I've done it with an AdWhirlView, hide it below the screen, then animate it up;
AdWhirlView *adWhirlView = [AdWhirlView requestAdWhirlViewWithDelegate:self];
adWhirlView.delegate = self;
adWhirlView.frame = CGRectMake(0, 430+kAdWhirlViewHeight, kAdWhirlViewWidth, kAdWhirlViewHeight);
[self.parentViewController.view insertSubview:adWhirlView belowSubview:self.view];
[UIView beginAnimations:#"AdWhirlIn" context:nil];
[UIView setAnimationDuration:.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
adWhirlView.frame = CGRectMake(0, 430, kAdWhirlViewWidth, kAdWhirlViewHeight);
[UIView commitAnimations];