I have an app, it runs in landscape mode, I hold it in landscape mode when debugging on my phone. I pick up the center value from the UIView on my main view controller, I need this to put items in the center of the screen, and since it is universal I need this to be variable and not set to iPhone screen sizes.
When I do this and read the x and y from the CGPoint returned by view.center I get
x = 170
y = 240
The delegate is the one viewcontroller in my app, the center function is one of the object I want to move to the center.
- (void) center
{
CGPoint center = ((UIViewController*)delegate).view.center;
CGSize size = self.frame.size;
double x = center.x - size.width/2 - location.x;
double y = center.y - size.height/2 - location.y;
[self _move:1.0 curve:UIViewAnimationCurveEaseInOut x:x y:y];
}
- (void)_move: (NSTimeInterval)duration
curve:(int)curve x:(CGFloat)x y:(CGFloat)y
{
// Setup the animation
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:duration];
[UIView setAnimationCurve:curve];
[UIView setAnimationBeginsFromCurrentState:YES];
// The transform matrix
CGAffineTransform transform = CGAffineTransformMakeTranslation(x, y);
self.transform = transform;
// Commit the changes
[UIView commitAnimations];
}
Now to me this does not make much sense.
Use bounds, not frame. Frame is in the superview's coordinate system which for your root view is the window - this does not rotate in different orientations.
Bounds is in the views own coordinate system so is the appropriate rect to use when setting center on subviews, since center is also expressed in the superview's coordinate system.
Related
I am trying to animate a label across the screen however I cannot seem to get it work properly. Currently it animates off the view into the other views.
Also I cannot "stop" the animation when needed. I am using it in a music player to scroll the track name across the UIView and when I tap Next or Prev it must stop mid-animation and start again.
- (void)startAnimation {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:10];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationDidStop:)];
CGRect frame = trackName.frame;
frame.origin.x = -50;
trackName.frame = frame;
[UIView commitAnimations];
}
- (void)animationDidStop:(id)sender {
NSLog(#"animationDidStop");
CGRect frame = trackName.frame;
frame.origin.x = 194;
trackName.frame = frame;
[self startAnimation];
}
I assume what you are trying to do is animate the label so that it moves 50 pixels to the left. If so, you need to change the line:
frame.origin.x = -50
to
frame.origin.x -= 50;
The problem is that you are setting the new origin of the frame to -50, which is 50 pixels off the left side of the view. Instead you need to just subtract 50 pixels from it's current position so that it moves 50 pixels relative to where it was.
I have an image which is rotating and what I want is that a second image to be stuck on it and it rotate just as the first. Please, how can I do this?
I'm not at my computer so I can't test this, but I think it should get you what you want.
// assuming you already have your views
// viewOne, viewTwo
[viewOne addSubview:viewTwo]; // add viewTwo to viewOne
// let's assume that you call this code here one time per second
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
// when this is 1.0, the image will rotate 360
// ... when it is .5, it should rotate 180, etc...
float rotationFactor = 0.1f;
// viewTwo's rotationFactor will be added to view 1's in the transform below
float rotationFactor2 = 0.1f;
viewOne.transform = CGAffineTransformMakeRotation(M_PI_2 * rotationFactor);
viewTwo.transform = CGAffineTransformMakeRotation(M_PI_2 * (rotationFactor + rotationFactor2);
[UIView commitAnimations];
I'm trying to create a flip-and-scale animation between two view controllers. This seems possible using animation blocks available in iOS 4.0, but I'm still unsure how to implement it. I found this SO question which shows a flip animation.
Using this code, flipping between two views works fine, but scaling doesn't -- the flip animation completes and then the new view jumps to the correct size. How would I flip the view and scale it at the same time?
UIView *tempContainer = myView.contentView ;
[UIView transitionWithView:tempContainer
duration:2
options:UIViewAnimationOptionTransitionFlipFromRight
animations:^{
[[[tempContainer subviews] objectAtIndex:0] removeFromSuperview];
[tempContainer addSubview:myOtherViewController.view];
CGAffineTransform transform = CGAffineTransformMakeScale(4.0, 4.0);
tempContainer.transform = transform;
}
completion:^(BOOL finished){
[tempContainer release];
}];
I suppose this happens because the option UIViewAnimationOptionTransitionFlipFromRight somehow overrides everything else. Try using nesting animations or link them together
Here's how I flip and scale between two views of different sizes. I break the animation into a few parts. First I put the back view at the same location as the front view, but make it hidden. I then flip and scale the front view halfway. The back view is given the same transform as the front view, then rotated and scaled the rest of the way. Flipping back is basically the reverse.
I suppose you could use a different view controllers view property as the back view, but I haven't tried that.
// flip and scale frontView to reveal backView to the center of the screen
// uses a containerView to mark the end of the animation
// parameterizing the destination is an exercise for the reader
- (void)flipFromFront:(UIView*)frontView toBack:(UIView*)backView destination:(CGRect)destRect
{
float duration = 0.5;
// distance from center of screen from frontView
float dx = destRect.origin.x + CGRectGetWidth(destRect) / 2 - frontView.center.x;
float dy = destRect.origin.y + CGRectGetHeight(destRect) / 2 - frontView.center.y;
float scale = CGRectGetWidth(destRect) / CGRectGetWidth(frontView.bounds);
// this prevents any tearing
backView.layer.zPosition = 200.0;
// hide the backView and position where frontView is
backView.hidden = NO;
backView.alpha = 0.0;
backView.frame = frontView.frame;
// start the animation
[UIView animateKeyframesWithDuration:duration
delay:0.25
options:UIViewKeyframeAnimationOptionCalculationModeCubic
animations:^{
// part 1. Rotate and scale frontView halfWay.
[UIView addKeyframeWithRelativeStartTime:0.0
relativeDuration:0.5
animations:^{
// get the transform for the blue layer
CATransform3D xform = frontView.layer.transform;
// translate half way
xform = CATransform3DTranslate(xform, dx/2, dy/2, 0);
// rotate half way
xform = CATransform3DRotate(xform, M_PI_2, 0, 1, 0);
// scale half way
xform = CATransform3DScale(xform, scale/2, scale/2, 1);
// apply the transform
frontView.layer.transform = xform;
}];
// part 2. set the backView transform to frontView so they are in the same
// position.
[UIView addKeyframeWithRelativeStartTime:0.5
relativeDuration:0.0
animations:^{
backView.layer.transform = frontView.layer.transform;
backView.alpha = 1.0;
}];
// part 3. rotate and scale backView into center of container
[UIView addKeyframeWithRelativeStartTime:0.5
relativeDuration:0.5
animations:^{
// undo previous transforms with animation
backView.layer.transform = CATransform3DIdentity;
// animate backView into new location
backView.frame = destRect;
}];
} completion:^(BOOL finished) {
self.displayingFront = !self.displayingFront;
}];
}
// flip from back to front
- (void) flipFromBack:(UIView*)backView toFront:(UIView*)frontView
{
float duration = 0.5;
// get distance from center of screen to destination
float dx = backView.center.x - frontView.center.x;
float dy = backView.center.y - frontView.center.y;
backView.layer.zPosition = 200.0;
frontView.hidden = YES;
// this is basically the reverse of the previous animation
[UIView animateKeyframesWithDuration:duration
delay:0
options:UIViewKeyframeAnimationOptionCalculationModeCubic
animations:^{
[UIView addKeyframeWithRelativeStartTime:0.0
relativeDuration:0.5
animations:^{
CATransform3D xform = backView.layer.transform;
xform = CATransform3DTranslate(xform, -dx/2, -dy/2, 0);
xform = CATransform3DRotate(xform, M_PI_2, 0, 1, 0);
xform = CATransform3DScale(xform, 0.75, 0.75, 1);
backView.layer.transform = xform;
}];
[UIView addKeyframeWithRelativeStartTime:0.5
relativeDuration:0.0
animations:^{
backView.alpha = 0.0;
frontView.hidden = NO;
}];
[UIView addKeyframeWithRelativeStartTime:0.5
relativeDuration:0.5
animations:^{
self.hiddenView.alpha = 0.0;
frontView.layer.transform = CATransform3DIdentity;
}];
} completion:^(BOOL finished) {
self.displayingFront = !self.displayingFront;
}];
}
So I want to rotate a subview x degrees (or at least 90 degrees). I want the subwiew to rotate around the subview's bottom right corner. Is it possible to do this animated like in the picture below?
Thanks!
CGAffineTransform transform =
CGAffineTransformMakeRotation(angle);
yourSubView.transform = transform;
Yo can do it composing transforms. First translate to the rotation origin, then rotate, then transform back to the original center. The view you are rotating is v. It is inside an animation just for fun.
[UIView beginAnimations:nil context:NULL];
CGAffineTransform t = CGAffineTransformIdentity;
t =CGAffineTransformTranslate(t,- v.bounds.size.width/2, -v.bounds.size.height/2);
t = CGAffineTransformRotate(t, -M_PI/2);
t =CGAffineTransformTranslate(t,v.bounds.size.width/2, v.bounds.size.height/2);
v.transform = t;
[UIView commitAnimations];
I am using this code to zoom from a particular point
CGPoint getCenterPointForRect(CGRect inRect)
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
return CGPointMake((screenRect.size.height-inRect.origin.x)/2,(screenRect.size.width-inRect.origin.y)/2);
}
-(void) startAnimation
{
CGPoint centerPoint = getCenterPointForRect(self.view.frame);
self.view.transform = CGAffineTransformMakeTranslation(centerPoint.x, centerPoint.y);
self.view.transform = CGAffineTransformScale( self.view.transform , 0.001, 0.001);
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:kTransitionDuration];
self.view.transform = CGAffineTransformIdentity;
[UIView commitAnimations];
}
Its not working. What is the correct way to do zooming from a particular point.
I think that, if I've diagnosed your problem correctly, you're getting a scaling animation where the view starts tiny and at a point, then scales and moves to the centre of the screen exactly like you want, but the point it starts at is incorrect?
First of all, views scale around their centre. So if you took out the translation and hence reduced the code you have to:
self.view.transform = CGAffineTransformMakeScale( 0.001, 0.001);
And your view ends up taking up the whole screen then it'll remain centred on the middle of the screen, sort of a little as though it's a long way away and you're heading directly towards it.
Supposing you instead want it to grow and move to the centre of the screen from (x, y) then you need something more like:
CGPoint locationToZoomFrom = ... populated by you somehow ...;
CGPoint vectorFromCentreToPoint = CGPointMake(
locationToZoomFrom.x - self.view.center.x,
locationToZoomFrom.y - self.view.center.y);
self.view.transform = CGAffineTransformMakeTranslation(vectorFromCentreToPoint.x, vectorFromCentreToPoint.y);
self.view.transform = CGAffineTransformScale( self.view.transform , 0.001, 0.001);
Where locationToZoomFrom will be the initial centre of the view and its normal centre as per its frame will be the destination.