I have a UILabel I want to animate growing and shrinking. While the size changes I need the bottom left corner to remain static so that it always appears directly above a bottom toolbar. I am using the following code to make the label grow:
[UIView animateWithDuration:kAnimationDuration delay:0.0 options:UIViewAnimationCurveEaseInOut
animations:^{
CGFloat lblHeight = 42.0f;
[label setFrame:CGRectMake(0.0,
CGRectGetMaxY(self.view.bounds) - kBottomBarHeight - lblHeight,
CGRectGetMaxX(self.view.bounds),
lblHeight)];
} completion:^(BOOL finished) { }];
and to make it shrink I use the same logic except that lblHeight is set to 17.0f
The view correctly grows but when I try to shrink it the frame change animation is not animated. It blips into the new size and then animates into the new origin/location. I need the frame change to be animated. Can anyone see what I'm doing wrong?
After some tinkering I've managed to get the desired behavior by doing the following.
In the expand method, I use the UIView animation to alter the frame.
In the shrink method, I use the UIView animation to alter the bounds and center.
I'm a little baffled as to why this works but trying to shrink with the frame does not. If anyone can share some insight into this that would be great.
You should not really use frames to animate, rather you should use the transform property of your label.
However, since you want one corner to remain static, I think its best you use Core Animation. CALayer has a property called anchorPoint that determines which point a layer will rotate with respect to, and I'm pretty sure it is also valid for grow/shrink effects.
Related
I am talking about that effect when user presses button to take photo, it shrinks and moves to toolbar? How is this achieved in general?
You can create this by both scaling (applying a transform) and moving (animating the position) of the image.
I wrote about a similar animation (the Open in Background animation from Safari on iPhone) in this blog post. Not all of the code is necessary but some part of it will be useful for the animation you are trying to do.
You should
Calculate the scale factor to make the image the appropriate size
Calculate the path you want to animate the image along.
Animate a scale with the calculated scale factor
Animate a position animation along the path (using a CAKeyframeAnimation)
Since you are doing two animations at once you could benefit from using a CAAnimationGroup.
Since you are animating down to a toolbar which probably is another part of the view hierarchy than where the image is you may need to use method like
- (CGRect)convertRect:(CGRect)rect toView:(UIView *)view
and
- (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view
To translate coordinates between the different views.
so the shrink animation is achived by
[UIView beginAnimations:#"animationShrink" context:NULL];
[UIView setAnimationDuration:kSlideInAnimationDuration];
flipFlopContainer.transform = CGAffineTransformMakeScale(0.01, 0.01);
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(shrinkAnimationFinished:)];
[UIView commitAnimations];
after this animation in shrinkAnimationFinished method you need to define a path to follow and change the position of your view accroding to that path.
See the following thread for that animation
Resize and move a UIView with Core Animation (CAKeyFrameAnimation)
In some of the applications, I have seen that we can drag a view outside of its position using two fingers(in smooth motion). We are also able to resize, rotate and move it further. And when I take my fingers off the screen it just resized(also rotates) and go backs to its original position by itself in a smooth motion.
How can I do this kind of animation? Is there any sample available? OR just telling me how the flow actually is will also be really helpful.
UIViews are animatable simply by setting properties.
[UIView animateWithDuration:0.5 animations:^{
myView.frame = CGRectMake(50, 50, 100, 200);
myView.layer.affineTransform = CGAffineTransformMakeRotation(M_PI);
}];
Look up animateWithDuration in the docs for more options and examples.
I am creating a view and having it move on to the screen from left to right. I had a hard time getting it to work the way I wanted but when I did I was baffled at the way it worked.
I thought I would have to create the view off screen to the left then use CGAffineTransformTranslate to move it onto the screen. But instead I am creating it on the screen, but it still works great. I am a bit confused.
Here I am creating the view...
profileViewControllerForIPad = [[ProfileViewController alloc] initWithFrame:CGRectMake(0, 0, 512, 446)];
As you can see the origin is 0,0. So on screen, right?
Here is the thransform...
[UIView animateWithDuration:0.5
animations:^{
self.view.transform = CGAffineTransformTranslate(CGAffineTransformIdentity,self.view.frame.size.width, 0.0);
}
];
As you can see I am setting the tx value to the width of the CGAffineTransformTranslate which I thought was the value for the number of pixels you wanted it to move from it's current position, origin.x of 0, which I expected would move it to the middle of the screen somewhere. Instead, it slides right in with it's new origin.x right at 0 where I want it.
BTW CGAffineTransformIdentity works great sliding the view right back off the screen.
Can someone explain this to me. The docs seem to say something different.
Thanks,
John
I think I understand it now. I think it depends on when you execute CGAffineTransformTranslate.
If you are creating the object and call CGAffineTransformTranslate before you add it to it's superview, when you add it to it's superview it will display at a position that will allow it to move to it's defined position the amount and direction defined in the CGAffineTransformTranslate call.
If on the other hand the object you want to move is already being displayed, the object will be moved from it's current position to the new position.
In my case where I was creating a new UIView and wanted it to slide in from the left side of the screen, if I called CGAffineTransformTranslate at the same time that I created and added the view, I would have to define the view's frame at it's final on screen location.
Alternatively one could call CGAffineTransformTranslate in a timer method. In this case you would define the view's frame off screen, add it to the display and create the timer. The timer method would then move it on screen with CGAffineTransformTranslate.
I think you can animate the frame property (- animateWithDuration:animations:) of your viewControllers -view instead of using a transform, which is much easier to use and understand.
What would be the best way to make a main menu for a game? I would prefer it to be UIButtons. More specifically, what would be the best way of animating the buttons? For example, an animation on the view load of the buttons going in, then the buttons going out when a menu option is selected and then new buttons (the submenu) animated back in. I have never done any animating before so I would like to know the best way. Thanks
This type of animation is very easy using UIKit:
[UIView animateWithDuration:0.5 animations:^{
button1.frame = <new frame>;
button2.frame = <new frame>;
}];
This will animate the frame from the current frame, to the specified frame over the given duration (0.5 seconds). If the current frame is offscreen and the new frame is the final position you want then the buttons will move to their correct position over 0.5 seconds.
The following properties of UIView are animatable in this fashion:
frame
bounds
center
transform
alpha
backgroundColor
contentStretch
The Animations section of the View Programming Guide has more info.
Is there a way to make drawRect animate FROM THE PREVIOUS SCENE to the next one?
(Amazingly) you can animate inside drawRect - try it. You can fade, translate or animate any other property.
However, it starts "from fresh", from blank. So for example if you put a fade-in animation block in drawRect, the previous scene with disappear and the new scene will fade up from white.
I want the screen to fade from the previous image (drawn in the previous cycle of drawRect) to the new image I have just drawn ... err, am drawing.
Is there a way to do that, perhaps trickily by manipulating what's going on with drawRect?
This would seem to be a very common use case - blending from one scene to the next.
Does anyone know the secret?
Of course, obviously this can be done in the core animation milieu or in many other ways, but having drawRect fade from one drawRect to the next is an obvious idea. Cheers.
Astounding update thanks to the genius of WrightCS.....
Thanks only to WrightCS, we now know that drawRect handles animations perfectly. Simply paste this code at the end of any drawRect and try it:
self.alpha = 0.0;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:2];
self.alpha = 1.0;
[UIView commitAnimations];
it treats the entire drawRect, no matter how complex, as one enormous block and it wraps it in that animation. Yes, it even includes painted in offscreen areas, bitmap rendering or anything else. Everything gets animated. Who knew?
The problem at hand - how to make it start the animation from the previous scene rather than start from blank?
Drawrect Is invisible. It happens in the 'backbuffer' which the iOS displays on screen only when you're ready with drawRect. So you can definitely not animate while in drawrect. However, you can commit animation instrucions from just about anywhere, including drawrect. But the animation will be performed afterwards.
Animation requires timing and showing different frames to the user.
You CAN do that all by yourself (constantly forcing a redraw and doing something slightly different in drawrect each the time) but that's a lot of work, especialy if you want it done right.
Luckily iOS has many animation effects programmed for you. Either using Core Animation, or the (more simple and basic) animation in UIKit. But since it works by animating certain properties of views (eg the alpha of a whole view, or the rotation of a whole view, ...) you might need to rearrange your views and subviews to make good use of it.
E.g. Each horse limb is separate subview and you animate their transformations (no redraw needed, iOS will do the rest)
E.g. The old and new frame are two separate views and you animate the new frame (which is on top) from alpha 0 to alpha 1.
You can animate the alpha:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:2.0];
myObject.alpha = 0.0;
[UIView commitAnimations];
if you are under iOS 5.0+, you can use the following:
...
[UIView animateWithDuration:0.3
delay:0.0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
//do your stuff here
}completion:^(BOOL finished) {
//completition stuff go here
}];
...
The best thing you can do is to use two UIView instances and animate between them.
When you are starting the animation you have to know which is the original and final state of the animation. That's difficult if it's only one view.