I have a problem with CAAffineTransformationMakeRotation. M trying to rotate a UIView with 22.5 degrees in ViewDidLoad, and after a delay of 1 sec,the View flyin to the screen.
the code is:
-(void)ViewDidiLoad{
imgView1 = [[UIView alloc] initWithFrame:CGRectMake(20,150,.1,400)];
[imgView1 setBackgroundColor:[UIColor blackColor]];
[self.view addSubview:imgView1];
CGAffineTransform trans = CGAffineTransformMakeRotation(3.14159/8);
imgView1.transform = trans;
[self performSelector:#selector(img1_enter) withObject:nil afterDelay:1];
}
-(void)img1_enter{
CGRect frame = [imgView1 frame];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:2.99];
frame.origin.x = 550;
[UIView commitAnimations];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:2.99];
[imgView1 setFrame :frame];
[UIView commitAnimations];
}
The problem is that when this view fly's in..its width and height changes. I've tried without rotating the View(i.e without AffineTransformation), it works properly.
Is there any other method to rotate the View??
You could incorporate the already existing transform to preserve the current size respectively aspect ratio:
imgView1.transform = CGAffineTransformConcat(trans, imgView1.transform);
Also the documentation of the UIView class says that the frame property is undefined if the transform is not the identity transform, so you must not use it after you applied a rotation.
The frame-rectangle represents the position and size of the view within the coordinate-system of its superview. The bounds-rectangle represents the inner coordinate-system of the view, so the bounds-rectangle is sort of responsible for the actual pixel-amount (respectively the amount of columns and rows) of the view.
If the contentMode is set to UIViewContentModeRedraw and you alter the frame-rectangle, then the size of the bounds-rectangle automatically gets adjusted that it fits the size of the frame-rectangle and vice-versa, else the bounds-rectangle stays untouched. For rendering the difference between the frame-rectangle and the bounds-rectangle is compensated by an automatically created transform-matrix.
The last two sentences are only true, iff the transform-property of the view is the identity matrix. If it isn't, the frame-property is invalid and you alone are responsible to provide a proper transform from the coordinate-system of the view to the coordinate-system of its super-view. So if you want to apply a rotation, you also have apply a proper translation and scaling to get the view where you want it to be relative to the coordinates of its super-view.
So in your case, you could set the bounds-rectangle to CGRectMake(-width/2, -height/2, width, height) and set its transform to
CGAffineTransformConcat(
CGAffineTransformMakeRotation(angle),
CGAffineTransformMakeTranslation(x, y)
)
, where x and y are the center-coordinates of the view within the coordinate-system of its super-view.
Related
I have a UIView which I want to grow from it's center when a user touches it. The problem is that when animating it the view expands left and then moves to the right, whereas I want it to expand to the left and right, while keeping the center point the same.
This is the code I have at the moment:
[UIView animateWithDuration:1 animations:^(void) {
[view setFrame:CGRectMake(-10, 0, 320, view.frame.size.height)];
}];
I didn't think it was going to be difficult to do this, but it seems it is. Short of animating it manually with a timer I have no idea how to get it to expand from it's center.
I am not quite sure why it's working for you in a weird manner. Did you alter the anchorPoint property in any way? Otherwise it should grow from center.
Does doing
CGRect newFrame;
newFrame = CGRectInset(view.frame, -10, -30);
[UIView animateWithDuration:1 animations:^(void) {
view.frame = newFrame;
}];
also give you the same result? What about this?
[UIView animateWithDuration:1 animations:^(void) {
view.transform = CGAffineTransformScale(view.transform, 1.1, 1.1);
}];
Try the code given by #Deepak Danduprolu and also don't forgot to UnCheck the "Use AutoLayout" checkbox in the show file inspector window of the storyboard.
It works for me.
Just offset the X,Y position of the view. Lets say you're DECREASING both the width and height of the frame by 20 points: you should then ADD 10 points to both the X and Y position of the frame.
I am having a label in a view.After scaling the view, the label looks little blurred,the resolution is lost.How to retain the resolution after scaling.
Here is my code for scaling
secondView.transform = CGAffineTransformIdentity;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
secondView.transform = CGAffineTransformMakeScale(2 ,2);
[UIView commitAnimations];
[self.view bringSubviewToFront:secondView];
I set the ContentScaleFactor property of the label to retain the resolution of the label after scaling .
[label setContentScaleFactor:2];
Create a label of big size itself, scale down using transformations when you add it to the view.
So at the run time when the view will scaleup the label's resolution will not be lost.
This is one of the approach.
Thanks
I have a UIView called goalBar which is being animated by increasing the size of the frame according to a float value called destination:
CGRect goalBarRect = CGRectMake(0, 0, destination, 29);
[UIView beginAnimations:#"goal" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView setAnimationDuration:2.0f];
goalBar.frame = goalBarRect;
[UIView commitAnimations];
The animation works perfectly and the rectangular view increases its width over the course of the animation (from 0 to the value for destination).
However, I wish to be able to extract the values for the frame of the UIView being animated (i.e. goalBar) as the animation takes place. By that I mean that I wish to place the value of the width for the animated frame in a separate UILabel so that the user sees a counter that provides the width of the UIView as it's being animated.
Any help on how to do the above would be gratefully received.
How about observing the frame property of the view. So that you get callbacks when it changes.
See Key-Value Observing.
I've looked into this and it seems that it is not possible to get updates on the state of the components being animated during the UIView animation process.
I'm planning to create a game like hangman. And I want every character appear from the top, like flying from the top. Do I have to make a transition or just hard code the animation for this implementation?
Thanks.
Put each character in its own UIView instance and animate the center property.
//let's say we have a custom UIView subclass that displays a character called 'MYCharacterView'
MYCharacterView * view = [[MYCharacterView alloc] initWithFrame:CGRectMake(50.0, -10.0, 20.0, 20.0);
// ... configure the view here, e.g., set the character, etc. ...
[UIView beginAnimations:nil context:nil];
//animate the view from its current position off the top of the screen to 50, 200
//over 2 seconds
[view setCenter:CGPointMake(50.0, 200.0)];
[UIView setAnimationDuration: 2.0];
[UIView commitAnimations];
Hope that helps!
I am looking for a way to do a UIViewAnimationTransitionCurlUp or UIViewAnimationTransitionCurlDown transition on the iPhone but instead of top to bottom, do it from the left to right (or top/bottom in landscape mode). I've seen this asked aroud the internet a few times but none sems to get an answer. However I feel this is doable.
I have tried changing the View's transform and the view.layer's transform but that didn't affect the transition. Since the transition changes when the device changes orientation I presume there is a way to fool the device to use the landscape transition in portrait mode and vice versa?
It's possible to do curls in any of the four directions by using a container view. Set the container view's transformation to the angle you want and then do the curl by adding your view to the container view, not your app's main view which does not have a transformed frame:
NSView* parent = viewController.view; // the main view
NSView* containerView = [[[UIView alloc] initWithFrame:parent.bounds] autorelease];
containerView.transform = CGAffineTransformMakeRotation(<your angle here, should probably be M_PI_2 * some integer>);
[parent addSubview:containerView];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:containerView cache:YES];
[containerView addSubview:view];
[UIView commitAnimations];
I actually managed to achieve this effect by changing the orientation of my UIViewController. The strange thing is, I had my controller nesten in another one when it wasn't working, but when I set him as the immediate view controller, it worked.
Code that does it:
In a UIViewController that is the main view controller in my app delegate and only allows landscape orientation (as you see in the 2nd method below) I have the following:
-(void)goToPage:(int)page flipUp:(BOOL)flipUp {
//do stuff...
// start the animated transition
[UIView beginAnimations:#"page transition" context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationTransition:flipUp ? UIViewAnimationTransitionCurlUp : UIViewAnimationTransitionCurlDown forView:self.view cache:YES];
//insert your new subview
//[self.view insertSubview:currentPage.view atIndex:self.view.subviews.count];
// commit the transition animation
[UIView commitAnimations];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
I also struggled with this. To get the curl to come from the right or left you can create an intermediate view and transform it. So, let's say the view you're transitioning (myView) is a child of the main window (parentView):
-parentView
-->myView
You will insert an intermediate view in between (easily done in Interface Builder):
-parentView
-->containerView
--->myView
Then, use the following code to flip the container 90 deg left and the transitioned view 90 deg right:
containerView.transform = CGAffineTransformMakeRotation(-M_PI_2);
myView.transform = CGAffineTransformMakeRotation(M_PI_2);
myView will still appear upright to the user but the transition will think it's applied at 90 degrees from the left.
Note that depending on how auto-scaling your views are, you might have to fix the frame sizes after applying the transform, eg
containerView.frame = CGRectMake(0.0, 0.0, 768.0, 1024.0);
myWebView.frame = CGRectMake(0.0, 0.0, 768.0, 1024.0);
Hope this helps. The is the closest you can get to UIViewAnimationTransitionCurlLeft and UIViewAnimationTransitionCurlRight.
I tried the solution of fluXa on iOS5 (So I had to use [UIView trans......]) but it didn't work: the curl still went up or downwards. Apparently the transition now don't take the transform of the view into account. So in case someone else wants to do the same trick on iOS5, the solution is to add another container in between and animate the transition from there.
Here is my code, which is a bit specific since I want to curl 'up' to the left, but with the lower corner curling. As if I am tearing a page out of a note book.
UIView* parent = self.view; // the main view
CGRect r = flipRectSize(parent.bounds);
UIView* containerView = [[UIView alloc] initWithFrame:r];
CGAffineTransform t = CGAffineTransformMakeRotation(-M_PI_2);
t = CGAffineTransformTranslate(t, -80, -80);
containerView.transform = CGAffineTransformScale(t, -1, 1);
[parent addSubview:containerView];
UIView* container2 = [[UIView alloc] initWithFrame:r];
[containerView addSubview:container2];
UIImageView* v = [[UIImageView alloc] initWithFrame:r];
v.image = [UIImage imageWithCGImage:contents.CGImage scale:contents.scale orientation:UIImageOrientationLeftMirrored];
[container2 addSubview:v];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.001 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[UIView transitionWithView:container2
duration:DURATION_CURL_ANIMATION
options:UIViewAnimationOptionTransitionCurlUp
animations:^{
[v removeFromSuperview];
} completion:^(BOOL finished) {
if (completion) {
completion(finished);
}
[containerView removeFromSuperview];}];});
Notes:
I must admit that the affine transform translate (80,80) doesn't make sense in my mind, but it is necessary for iphone, probably won't work on iPad.
flipSizeRect flips the width and height of a rectangle (you already got that, right?)
the dispatch_after is necessary because I added the container and then want to remove a view from the hierarchy. If I leave out the dispatch nothing animates. My best guess is that we first need to let the system do a layout pass before we can animate a removal.
I don't think there is a way beyond writing a custom animation.
More importantly you probably shouldn't try to it. The curl up and curl down are part of the user interface grammar that tells the user that a view is being lifted up or put down over the existing view. It's supposed to be like a sticky note being put down and then removed. A left<->right curl will most likely be interpreted as the something like ripping a page out of a book. It will confuse users.
Whenever you find yourself trying to do something in the interface that the standard API doesn't do easily, you should ask yourself whether such a novel method will communicate something important to user and whether it is similar to the existing interface grammar. If not, then you shouldn't bother.
Unusual interfaces have an initial wow factor but they lead to frustration and errors in day-to-day use. They can also cause Apple to refuse your app.