Using cgaffinetransformmakescale and cgaffinetransformmakerotation deforms my view - objective-c

I have a simple UIView:
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
view.backgroundColor = [UIColor greenColor];
[self.view addSubview:view];
self.someView = view;
Then I do this
[UIView animateWithDuration:10
delay:1
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
self.someView.center = CGPointMake(CGRectGetWidth(self.view.bounds) - CGRectGetWidth(self.someView.frame) / 2, 150);
CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI);
self.someView.transform = CGAffineTransformScale(transform, 2, 0.5);
}
completion:^(BOOL finished) {
}];
While is executed this simple animation, someView is deformed. As far as I know it should rotate and change it's size. I can't understand why is it happening so, how can i fix it?
Thanks

The problem is animating a combined scaling and rotation. The end result is the same as animating them separately, but the frames in between are not easily defined. So the animation framework makes a guess, and it is not what you are expecting.
If you want the animation to show a rotation and scaling separately, you need to apply them separately to the view hierarchy. For example:
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
view.backgroundColor = [UIColor greenColor];
[self.view addSubview:view];
self.someView = view;
UIView *innerView = [[UIView alloc] initWithFrame:view.bounds];
innerView.backgroundColor = [UIColor blueColor];
[view addSubview:innerView];
self.someInnerView = innerView;
The animation splits the transform:
[UIView animateWithDuration:10
delay:1
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
self.someView.center = CGPointMake(CGRectGetWidth(self.view.bounds) - CGRectGetWidth(self.someView.frame) / 2, 150);
self.someView.transform = CGAffineTransformMakeRotation(M_PI);
self.someInnerView.transform = CGAffineTransformMakeScale(2, 0.5);
}
completion:^(BOOL finished) {
}];

Related

UIView animation and transform cause a weird position offset

http://childhoodgamedev.qiniudn.com/xincheng_testGif.gif
UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(250, 250, 200, 100)];
label.text = #"Hello world!";
label.textColor = [UIColor blackColor];
label.textAlignment = NSTextAlignmentLeft;
label.backgroundColor = [UIColor clearColor];
label.font = [UIFont systemFontOfSize:25];
[self.view addSubview:label];
CGAffineTransform transform = CGAffineTransformIdentity;
label.transform = CGAffineTransformScale(transform, 2, 2);
[UIView animateWithDuration:4.0 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
label.transform = CGAffineTransformTranslate(label.transform, -100, 0);
} completion:^(BOOL finished) {
if (finished) {
NSLog(#"label %f %f %f %f", label.frame.origin.x, label.frame.origin.y, label.frame.size.width, label.frame.size.height);
[UIView animateWithDuration:3.0 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
NSLog(#"label %f %f %f %f", label.frame.origin.x, label.frame.origin.y, label.frame.size.width, label.frame.size.height);
label.transform = CGAffineTransformTranslate(label.transform, 100, 0);
} completion:NULL];
}
}];
There is UILabel instance named label, it's scaled to 2 ratio by CGAffineTransformScale. Then it moves from right to left, when the animation is completed, then it moves from left to right.
But the strange point is: It looks not the same position, which is the end point of animation(right to left), the start point of animation(left to right). But the NSLog tells me, they are in the same position.
http://childhoodgamedev.qiniudn.com/xincheng_QQ20150306-1.png
When I comment the state label.transform = CGAffineTransformScale(transform, 2, 2);, everything is fine. When the label change direction to move, the end position of right->left animation is just the start position of left->right animation.
So I think the problem is caused by CGAffineTransformScale. Any ideas?

How can I move a UIView to an end location but make it slow down as it approaches it?

I'm trying to move a box from point A = (0, 0) to B = (0, 1000) but I want to slow down as it approaches point B. I tried UIViewAnimationOptionCurveEaseOut but it seems to be moving at a constant velocity.
UIView *box = [[UIView alloc] init];
box.frame = CGRectMake(0, 0, 500, 500);
box.backgroundColor = [UIColor redColor];
[self.view addSubview:box];
// Animation
[UIView animateWithDuration:0.3
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
box.frame = CGRectMake(0, 1000, box.frame.size.width, box.frame.size.height);
} completion:nil];
Any ideas?
The easiest solution is to do the animation in multiple stages, with different speed, e.g. like this:
// Animation stage 1
[UIView animateWithDuration:0.1 //First half is fast
delay:0.0
options:UIViewAnimationOptionCurveEaseIn
animations:^{
box.frame = CGRectMake(0, 500, box.frame.size.width, box.frame.size.height);
} completion:^(BOOL finished) {
// Animation stage 2
[UIView animateWithDuration:0.2 //Second half slower
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
box.frame = CGRectMake(0, 1000, box.frame.size.width, box.frame.size.height);
} completion:nil];
}];
It should be possible to get a smooth animation by playing around with it a bit.
If this is iOS 7+, use spring animations. Add this code to viewDidAppear: to test it out and see the difference between using a spring vs. a simple ease out curve.
Also note that Apple really encourages the use of spring animations going forward, since almost all (or all?) of their animations in iOS 7+ are done with springs.
UIView *fooView = [[UIView alloc] initWithFrame:CGRectMake(50, 100, 50, 50)];
fooView.backgroundColor = [UIColor redColor];
[self.view addSubview:fooView];
[UIView animateWithDuration:1
delay:1
usingSpringWithDamping:1
initialSpringVelocity:1
options:0
animations:^{
fooView.frame = CGRectMake(50, 400, 50, 50);
}
completion:nil];
UIView *barView = [[UIView alloc] initWithFrame:CGRectMake(200, 100, 50, 50)];
barView.backgroundColor = [UIColor redColor];
[self.view addSubview:barView];
[UIView animateWithDuration:1
delay:1
options:UIViewAnimationOptionCurveEaseOut
animations:^{
barView.frame = CGRectMake(200, 400, 50, 50);
}
completion:nil];
If you're not satisfied with built-in easing functions you can create your own. You want something related to CAMediaTimerFunction or CAKeyframeAnimation. You can read about it here and here. There's also some good answers here.

Rotate between 2 views

I have two views. How do I transition between them by rotation? I want to rotate the first view to get the second view... Thanks.
I tried using [UIView transitionFromView but it does not have a rotation parameter.
It might be what you are expecting. But, not quite as you expected since it is not using transition animation simply adding or removing the subviews.
UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(60, 140, 200, 200)];
view1.backgroundColor = [UIColor greenColor];
[self.view addSubview:view1];
UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(60, 140, 200, 200)];
view2.backgroundColor = [UIColor redColor];
[self.view addSubview:view2];
view2.alpha = 0;
[UIView transitionWithView:view1 duration:2.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
view1.transform = CGAffineTransformMakeRotation(M_PI/2);
} completion:^(BOOL com){
view2.alpha = 1;
[view1 removeFromSuperview];
}];

I need to popup actionsheet above tabbar in my present viewcontroller, but it should not overlap tabbar(i need to see tabbar clearly)

I need to popup transperant actionsheet above tabbar in my present viewcontroller, but it should not overlap tabbar(i need to see tabbar clearly).
To create a transparant background on a UIActionsheet you have to set the delegate and then you can do:
- (void)willPresentActionSheet:(UIActionSheet *)actionSheet {
[actionSheet.layer setContents:nil];
}
To create a custom UIView that animates in from the bottom you can do>
bottomView = [[UIView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height, self.view.frame.size.width, 250)];
bottomView.backgroundColor = [UIColor redColor];
bottomView.hidden = YES;
[self.view addSubview:bottomView];
UIButton *testButton = [UIButton buttonWithType:UIButtonTypeCustom];
testButton.frame = CGRectMake(20, 50, 280, 40);
testButton.backgroundColor = [UIColor greenColor];
[bottomView addSubview:testButton];
[self animateBottomViewIn];
And have the following methods:
-(void)animateBottomViewIn
{
bottomView.hidden = NO;
[UIView animateWithDuration:0.3 animations:^{
bottomView.frame = CGRectMake(0, self.view.frame.size.height - bottomView.frame.size.height, self.view.frame.size.width, bottomView.frame.size.height);
} completion:^(BOOL finished) { }];
}
-(void)animateBottomViewOut
{
[UIView animateWithDuration:0.3 animations:^{
bottomView.frame = CGRectMake(0, self.view.frame.size.height, self.view.frame.size.width, bottomView.frame.size.height);
} completion:^(BOOL finished) {
bottomView.hidden = YES;
}];
}

How to animate zooming UIView WITH SUBVIEWS?

This code does the following: It takes a 'snapshot' of a NavigationController meant to disappear. Then the snapshot is added to the view of a container view controller, slides away and reveals the new NavigationController. To create the 'Pop-Out-Effect' the midAnFrame makes the view a bit bigger than the actual view. After that postAnFrame provides the sliding out of the container view's frame. Works great, the only problem is that the subviews of animationContainer don't resize like their superView during the animation.
- (void)bringUpSettingsNavigationController {
CGFloat gradientWidth = 20;
CGFloat frameIncrease = 10;
CGRect preAnFrame = CGRectMake(- gradientWidth, 0, self.view.frame.size.width + gradientWidth, self.view.frame.size.height);
CGRect midAnFrame = CGRectMake(-(frameIncrease + gradientWidth), - frameIncrease, preAnFrame.size.width + (2*frameIncrease), preAnFrame.size.height + (2*frameIncrease));
CGRect postAnFrame = CGRectMake(midAnFrame.size.width, midAnFrame.origin.y, midAnFrame.size.width, midAnFrame.size.height);
UIView *animationContainer = [[UIView alloc]initWithFrame:preAnFrame];
animationContainer.backgroundColor = [UIColor clearColor];
animationContainer.autoresizesSubviews = YES;
self.topImageView = [[UIImageView alloc]initWithImage:[self topImageFromView:self.view]];
self.topImageView.frame = CGRectMake(gradientWidth, 0, preAnFrame.size.width - gradientWidth, preAnFrame.size.height);
[animationContainer addSubview:self.topImageView];
self.topImageView.clipsToBounds = YES;
UIView *gradientView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, gradientWidth, preAnFrame.size.height)];
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = gradientView.bounds;
gradientLayer.colors = [NSArray arrayWithObjects:(id)[[UIColor clearColor] CGColor], (id)[[UIColor colorWithWhite:0 alpha:.5] CGColor], nil];
gradientLayer.startPoint = CGPointMake(0, 0.5);
gradientLayer.endPoint = CGPointMake(1.0, 0.5);
[gradientView.layer insertSublayer:gradientLayer atIndex:0];
gradientView.backgroundColor = [UIColor clearColor];
[animationContainer addSubview:gradientView];
gradientView.clipsToBounds = YES;
[self.view addSubview:animationContainer];
BYSettingsNavigationController *settingsNavigationController = [[BYSettingsNavigationController alloc]initWithRootViewController:[[BYSettingsViewController alloc]init]];
[self addChildViewController:settingsNavigationController];
settingsNavigationController.view.frame = self.view.bounds;
[self.view insertSubview:settingsNavigationController.view belowSubview:animationContainer];
[settingsNavigationController didMoveToParentViewController:self];
[UIView animateWithDuration:0.2 animations:^{
animationContainer.frame = midAnFrame;
} completion:^(BOOL finished) {
[UIView animateWithDuration:.5 animations:^{
animationContainer.frame = postAnFrame;
} completion:^(BOOL finished) {
[self.topImageView removeFromSuperview];
[gradientView removeFromSuperview];
self.topImageView = nil;
}];
}];
[self.currentNavigationController willMoveToParentViewController:nil];
[self.currentNavigationController.view removeFromSuperview];
[self.currentNavigationController removeFromParentViewController];
}
Thanks in advance for your ideas and have a great 2013!
Dario
What your doing is not zooming in , your just changing the frame size.
To zoom in you need to change the transformation of the view.
What you need to do is something along this line:
view.transform = CGAffineTransformMakeScale (2.0 , 2.0);
for example to zoom X2