Animate UIView with Anchor Point and stretchable image - ios

I'm trying to animate a bar chart where the images rise from the bottom. After a few hours, I'm seeing this is not an easy thing to achieve.
I simply want to do one thing:
Create an animation that scales up from a bottom center anchor point.
- (void)startCharts{
//set the stretchable images
UIImage* stretchGray = [UIImage imageNamed:#"rescueGrayChart"];
stretchGray = [stretchGray resizableImageWithCapInsets:UIEdgeInsetsMake(50, 0, 10, 0) resizingMode:UIImageResizingModeStretch];
self.grayChart.image = stretchGray;
//set the start frame and anchor point
CGRect gframe = self.grayChart.frame;
CGPoint bottomCenterGray = CGPointMake(CGRectGetMidX(gframe), CGRectGetMaxY(gframe));
self.grayChart.layer.anchorPoint = CGPointMake(0.5, 1);
[UIView animateWithDuration:5
delay:0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
//this creates the issue where the image scales outwards from center (see image)
CGRect frame = self.grayChart.frame;
frame.size.height = 300;
self.grayChart.frame = frame;
//this animates up from bottom, but stretches the image
/*
[CATransaction begin];
self.grayChart.layer.transform = CATransform3DMakeScale(1, 2, 1);
[CATransaction commit];
*/
}
completion:nil];
//readjust the frame
self.grayChart.layer.position = bottomCenterGray;}
** These images are screen shots taken during the animation
Thank you for your time.

Related

How to reduce the width of UIButton from both left and right with animation?

I have tried to reduce the width of UIButton from both left and right on clicking by using following code. But instead it just only shrinks the size of UIButton. The code is
-(void)loginclickAction:(id)sender
{
self.centerZoom = [CAKeyframeAnimation animationWithKeyPath:#"transform"];
self.centerZoom.duration = 1.5f;
self.centerZoom.values = #[[NSValue valueWithCATransform3D:CATransform3DMakeScale(1, 1, 1)],[NSValue valueWithCATransform3D:CATransform3DMakeScale(.9, .9, .9)],[NSValue valueWithCATransform3D:CATransform3DMakeScale(.8,.8, .8)],[NSValue valueWithCATransform3D:CATransform3DMakeScale(.7, .7, .7)],[NSValue valueWithCATransform3D:CATransform3DMakeScale(.6, .6, .6)],[NSValue valueWithCATransform3D:CATransform3DMakeScale(.5, .5,.5)]];
self.centerZoom.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
self.loginButton.transform = CGAffineTransformMakeScale(.5,.5);
self.loginButton.alpha = 1;
[self.loginButton.layer addAnimation:self.centerZoom forKey:#"buttonScale"];
[self.loginButton setUserInteractionEnabled:NO];
}
But the output is shrinking of the UIButton which i don't want. Please help me to find the way in reducing the width of the button animated.
Your transforms are all affecting multiple dimensions:
CGAffineTransformMakeScale(.5, .5);
this is scaling the width (x) and height (y), to scale only the width:
CGAffineTransformMakeScale(.5, 1);
and the same applies to
CATransform3DMakeScale(.9, .9, .9)
which is changing x, y and z dimensions and should be
CATransform3DMakeScale(.9, 1, 1)
You need a way by which you can scale the button only across the width.
Use below method which scales button horizontally from full width to half with animation-
-(void) reduceButtonWidthFromLeftAndRightWithAniamation:(UIButton *)button
{
[UIView beginAnimations:#"ScaleButton" context:NULL];
[UIView setAnimationDuration: 1.5f];
button.transform = CGAffineTransformMakeScale(0.5, 1.0);
[UIView commitAnimations];
}

UIView affine scaling transformation not animating properly in both directions

Within the viewDidLoad method, I create a CGPoint with the min X and Y values from the frame of a view. Then I set the anchorPoint of that views layer to 0,0 and its position to the CGPoint. Then I apply a CGAffineTransformScale to make it 0,0 (hide it.) Whenever a user touches a button I want it to animate from its anchorPoint 0,0 (top-left) to full width and height. If the user presses again animate it to 0,0 . However the view is out of place (from the anchor point change) and whenever I scale it on the button press the pop-up animation is not equal to when the layer is animated to hide. That is whenever the layer is made visible you can see it transition from no width and height to full width and height but when it is made invisible it just disappears.
heres viewWillLayoutSubviews
self.original = CGPointMake(CGRectGetMinX(self.menu.frame), CGRectGetMinY(self.menu.frame));
self.menu.layer.anchorPoint = CGPointMake(0, 0);
self.menu.layer.position = self.original;
self.menu.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0, 0);
This is on button click logic
if(self.isMenuVisible)
{
//hide menu
[UIView animateWithDuration:.5 animations:^{
self.menu.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0, 0);
}];
self.isMenuVisible = NO;
}
else
{
//show it
[UIView animateWithDuration:.5 animations:^{
self.menu.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1, 1);
}];
self.isMenuVisible = YES;
}
I don't know why zero width and height will cause no animation, but there is a workaround, it is making its width and height scale to 0.01 and when the animation is complete, hide the menu.
if (self.menu.hidden) {
[UIView animateWithDuration:.5 animations:^{
self.menu.hidden = NO ;
self.menu.transform = CGAffineTransformIdentity ;
}] ;
} else {
[UIView animateWithDuration:.5 animations:^{
self.menu.transform = CGAffineTransformScale(self.viewTest.transform, 0.01, 0.01) ;
} completion:^(BOOL finished) {
self.menu.hidden = YES ;
}] ;
}

Making a map bigger on tap - iOS

If I were wanting to make a map on my app bigger on touch, how would I do that? Would I use core animation? Example, I want to change my map from 50px height to 70px height on touch.
Thanks :D
First you need to know when a user is touching the MKMapView and in the method that the user touched the map you do that:
[UIView animateWithDuration:0.5 animations:^{
CGRect rect = myMapView.frame;
rect.size = CGSizeMake(50, 70);//Set to Bigger Size
myMapView.frame = rect;
}];
And when the user leaves the touch from map:
[UIView animateWithDuration:0.5 animations:^{
CGRect rect = myMapView.frame;
rect.size = CGSizeMake(50, 50);//Set to Original Size
myMapView.frame = rect;
}];
If you want the resize animated then yes you can use core animation. However if you just want to resize, you can just redraw the map view by doing the following:
CGRect oldFrame = yourMapView.frame;
oldFrame.size.height = oldFrame.size.height + 20; //aka 50+20 = 70
yourMapView.frame = oldFrame;

Animate size of View keeping its bottom left point fixed

I have a UIView at the bottom left of its superview, i.e.its frame is like
[myView setFrame:CGRectMake(0,superView.bounds.size.height-myViewHeight,myViewWidth,myViewHeight)];
I want to animate its size such that its bottom left point remains fixed at its position. I am not sure how to play with anchor point property of layers.
Currently I am increasing its size using the following lines of code.
[UIView animateWithDuration:0.2 animations:^{
[bottomLbl setFrame:CGRectMake(0, bottomView.bounds.size.height-250, 300, 250)];
This works fine but when I try to bring back to its original size, its bottom point gets lifted at the start of animation and settles down at the end of animation.
First define the point for the bottom left corner...
CGPoint bottomLeft = CGPointMake(0, 480); // this can be anything.
Then you need to define the sizes (big and small).
CGSize bigSize = CGSizeMake(280, 280);
CGSize smallSize = CGSizeMake(50, 50); // again, these can be anything.
Then animate them...
// create the rect for the frame
CGRect bigFrame = CGRectMake(bottomLeft.x, bottomLeft.y - bigSize.height, bigSize.width, bigSize.height);
CGRect smallFrame = CGRectMake(bottomLeft.x, bottomLeft.y - smallSize.height, smallSize.width, smallSize.height);
[UIView animateWithDuration:0.2
animations:^{
// set the rect onto the view
bottomLbl.frame = bigFrame;
// or
bottomLbl.frame = smallFrame;
}];
As long as you set the frame and the calculated end frames are correct and it's all done in one animation then the bottom left corner won't move.
If this doesn't help can you please post a video of what is happening (and all your animation code).
EDIT
[UIView animateWithDuration:0.2
delay:0.0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
// set the rect onto the view
bottomLbl.frame = bigFrame;
// or
bottomLbl.frame = smallFrame;
}
completion:nil];

Smooth scaling of vector graphics in UIView

So I have subclassed UIView and added some drawing code. I am scaling the resulting view up and down.
I would like this view to be resolution independent so that it is legible at any size, and I won't need to manage multiple images etc. etc.
As a test I made up a bit of drawing code that looks like this.
It creates concentric ovals that fit within whatever frame size the UIView has.
Actually the outside ring is a little smaller than the frame so it isn't clipped. Fine for this. The actual graphic will be more complex and will contain text which must be readable at small sizes and things of that nature.
- (void)drawRect:(CGRect)rect
{
UIColor* color = [UIColor colorWithRed: 0.833 green: 0.833 blue: 0.833 alpha: 1];
float width = self.bounds.size.width;
float height = self.bounds.size.height;
float scalePercent = 0.8;
for(int i = 0; i < 10; i++){
width = width * scalePercent;
height = height * scalePercent;
float x = (self.bounds.size.width - width) / 2;
float y = (self.bounds.size.height - height) / 2;
UIBezierPath* ovalPath = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(x, y, width, height)];
[color setStroke];
ovalPath.lineWidth = 2;
[ovalPath stroke];
}
}
Now here's the scaling:
- (void) makeBig{
[UIView animateWithDuration:0.5
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:(void (^)(void)) ^{
self.transform = CGAffineTransformMakeScale(2, 2);
}
completion:^(BOOL finished){
}];
}
When you run this the view zooms up, but it is pixelated. It's pixelated because the view has doubled in size but it's resolution has not changed.
So, here's how not to do it.
- (void) makeBig{
[UIView animateWithDuration:0.5
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:(void (^)(void)) ^{
self.transform = CGAffineTransformMakeScale(2, 2);
}
completion:^(BOOL finished){
CGRect targetFrame = self.frame;
self.transform = CGAffineTransformIdentity;
self.frame = targetFrame;
[self setNeedsDisplay];
}];
}
This works, but the fix is visible at the end of the animation when the resolution snaps back to screen resolution.
I could try pre-scaling the view up and pre-drawing at the final size then scaling it down and then running the animation to scale it back up again, but for various reasons that I can think of that sounds totally stupid. I suppose I could be wrong and it's the brightest idea since fire. I kind of doubt it though.
So how is a smooth scale of vector content done best?
View-based animation is really handy, but if I'm not mistaken it uses CABasicAnimation, which only uses a single keyframe. It'll be a little more code, but if you use a CAKeyframeAnimation instead, Core Animation will redraw the contents of the animated layer for each keyframe (you get to specify when those occur), so you can avoid the appearance of pixelation.

Resources