How to animate UIImageViews like hatch doors opening - ios

I'm trying to create an animation that would look like 2 french doors (or 2 hatch doors) opening towards the user.
I tried using the built in UIViewAnimationOptionTransitionFlipFromRight transition, but the origin of the transition seems to be the center of the UIImageView rather than the left edge. Basically I have 2 UIImageViews that each fill have the screen. I would like the animation to look like the UIImageViews are lifting from the center of the screen to the edges.
[UIView transitionWithView:leftView
duration:1.0
options:UIViewAnimationOptionTransitionFlipFromRight
animations:^ { leftView.alpha = 0; }
completion:^(BOOL finished) {
[leftView removeFromSuperview];
}];
Has anyone done something like this before? Any help would be awesome!
UPDATE:
Working code thanks to Nick Lockwood
leftView.layer.anchorPoint = CGPointMake(0, 0.5); // hinge around the left edge
leftView.frame = CGRectMake(0, 0, 160, 460); //reset view position
rightView.layer.anchorPoint = CGPointMake(1.0, 0.5); //hinge around the right edge
rightView.frame = CGRectMake(160, 0, 160, 460); //reset view position
[UIView animateWithDuration:0.75 animations:^{
CATransform3D leftTransform = CATransform3DIdentity;
leftTransform.m34 = -1.0f/500; //dark magic to set the 3D perspective
leftTransform = CATransform3DRotate(leftTransform, -M_PI_2, 0, 1, 0);
leftView.layer.transform = leftTransform;
CATransform3D rightTransform = CATransform3DIdentity;
rightTransform.m34 = -1.0f/500; //dark magic to set the 3D perspective
rightTransform = CATransform3DRotate(rightTransform, M_PI_2, 0, 1, 0);
rightView.layer.transform = rightTransform;
}];

First add the QuartzCore library to your project and #import <QuartzCore/QuartzCore.h>
Every view has a layer property with sub-properties that are animatable. This is where you'll find all the really cool stuff when it comes to animation capabilities (I suggest reading up on the CALayer class properties you can set - it will blow your mind - dynamic soft drop shadows on any view?)
Anyway, back on topic. To rotate your doors open in 3D, first position them as if they were closed, so with each door filling half the screen.
Now set their view.layer.anchorPoint properties as follows
leftDoorView.layer.anchorPoint = CGPoint(0, 0.5); // hinge around the left edge
rightDoorView.layer.anchorPoint = CGPoint(1.0, 0.5); // hinge around the right edge
Now apply the following animation
[UIView animateWithDuration:0.5 animations:^{
CATransform3D leftTransform = CATransform3DIdentity;
leftTransform.m34 = -1.0f/500; //dark magic to set the 3D perspective
leftTransform = CATransform3DRotate(leftTransform, M_PI_2, 0, 1, 0); //rotate 90 degrees about the Y axis
leftDoorView.layer.transform = leftTransform;
//do the same thing but mirrored for the right door, that probably just means using -M_PI_2 for the angle. If you don't know what PI is, Google "radians"
}];
And that should do it.
DISCLAIMER: I've not actually tested this, so the angles may be backwards, and the perspective may be screwy, etc. but it should be a good start at least.
UPDATE: Curiosity got the better of me. Here is fully working code (this assumes that the left and right doors are laid out in the closed position in the nib file):
- (void)viewDidLoad
{
[super viewDidLoad];
leftDoorView.layer.anchorPoint = CGPointMake(0, 0.5); // hinge around the left edge
leftDoorView.center = CGPointMake(0.0, self.view.bounds.size.height/2.0); //compensate for anchor offset
rightDoorView.layer.anchorPoint = CGPointMake(1.0, 0.5); // hinge around the right edge
rightDoorView.center = CGPointMake(self.view.bounds.size.width,self.view.bounds.size.height/2.0); //compensate for anchor offset
}
- (IBAction)open
{
CATransform3D transform = CATransform3DIdentity;
transform.m34 = -1.0f/500;
leftDoorView.layer.transform = transform;
rightDoorView.layer.transform = transform;
[UIView animateWithDuration:0.5 animations:^{
leftDoorView.layer.transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
rightDoorView.layer.transform = CATransform3DRotate(transform, -M_PI_2, 0, 1, 0);
}];
}
- (IBAction)close
{
[UIView animateWithDuration:0.5 animations:^{
CATransform3D transform = CATransform3DIdentity;
transform.m34 = -1.0f/500;
leftDoorView.layer.transform = transform;
rightDoorView.layer.transform = transform;
}];
}

Related

Scale animation in background from another anchorPoint

Ive done a Scaling animation for background image with an arrow in it,well by scaling the image(it includes the arrow) meaning its a whole background. it scales from the center of the background. but i want to start scaling from the center of arrow.
i want to achieve this :
Then to become with scale:
What i have to change in my code:
self.blueBackground.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1, 1);
[UIView animateWithDuration:5 animations:^{
self.blueBackground.transform = CGAffineTransformScale(CGAffineTransformIdentity, 30, 30);
} completion:^(BOOL finished) {
}];
With my current code the scale start from center of background so the arrow end up at the right (out the bounds of screen).
Try something like this:
- (void)animateArrow
{
self.blueBackground.transform = CGAffineTransformIdentity;
[UIView animateWithDuration:5 animations:^{
ScaleViewAboutPointInBounds(self.blueBackground, arrowCenter, 30);
} completion:^(BOOL finished) {
}];
}
static void ScaleViewAboutPointInBounds(UIView *view, CGPoint point, CGFloat scaleAmount)
{
CGFloat xAnchor = view.layer.anchorPoint.x * CGRectGetWidth(view.bounds);
CGFloat yAnchor = view.layer.anchorPoint.y * CGRectGetHeight(view.bounds);
CGFloat xOffset = point.x - xAnchor;
CGFloat yOffset = point.y - yAnchor;
CGAffineTransform shift = CGAffineTransformMakeTranslation(-xOffset, -yOffset);
CGAffineTransform unshift = CGAffineTransformMakeTranslation(xOffset, yOffset);
CGAffineTransform scale = CGAffineTransformMakeScale(scaleAmount, scaleAmount);
view.transform = CGAffineTransformConcat(shift, CGAffineTransformConcat(scale, unshift));
}
It's probably more general than what you need, and you could do it simpler, but this should work too. Just change the point to something that looks like the center of the arrow.

iOS Animated Bezier/Sine Curve

I am looking to animate a single-line bezier curve on a loop in iOS. The idea I have in my head resembles the Voice Control screen on the iPhone 4 before Siri. The curve does not need to react to anything ie. Audio, mic etc. It just needs to loop from screen left to screen right, and change the amplitude of the curve.
I have tried a couple tests and this is the closest I have come:
IOS : Animate transformation from a line to a bezier curve
I need to know how to animated the actual curve to appear as if it is moving, not just up and down.
If any one has some light to shed on this, that would be awesome!
Thanks!
Wow, I worked on the exact same thing today. :)
Check this :
So the view where I draw my waves, is initialized as :
_self_view = [[TDTWaveView alloc] initWithFrame:CGRectMake(-320, 174, 640, 200)];
Then in my viewDidLoad, I call [self animateWave]; once.
- (void)animateWave {
[UIView animateWithDuration:.5 delay:0.0 options:UIViewAnimationOptionRepeat|UIViewAnimationOptionCurveLinear animations:^{
_self_view.transform = CGAffineTransformMakeTranslation(+_self_view.frame.size.width/2, 0);
} completion:^(BOOL finished) {
_self_view.transform = CGAffineTransformMakeTranslation(0, 0);
}];
}
This gives the wave a sort of linear motion you might want.
As far as the code for the wave goes, I'll share the drawrect.
self.yc = 30//The height of a crest.
float w = 0;//starting x value.
float y = rect.size.height;
float width = rect.size.width;
int cycles = 7;//number of waves
self.x = width/cycles;
CGContextRef context = UIGraphicsGetCurrentContext();
CGMutablePathRef path = CGPathCreateMutable();
CGContextSetLineWidth(context, .5);
while (w <= width) {
CGPathMoveToPoint(path, NULL, w,y/2);
CGPathAddQuadCurveToPoint(path, NULL, w+self.x/4, y/2 - self.yc, w+self.x/2, y/2);
CGPathAddQuadCurveToPoint(path, NULL, w+3*self.x/4, y/2 + self.yc, w+self.x, y/2);
w+=self.x;
}
CGContextAddPath(context, path);
CGContextDrawPath(context, kCGPathStroke);

CATransform3DRotate effects gone after applying anchor point

EDIT with correct observation.
I used the following two snippets to rotate an UIImageView. After the stage1, I got the desired 3D effect: the view rotate (3D effect) and stretched out (larger size). On stage2, I am trying to swing the rightView with the hinge on the right.
If I applied the line that changes the anchor point, the view swings correctly (hinge on right) with one major issue: The view's size got restored back to original size (smaller) while the (rotation) 3D effect is still intact and then the swinging occurs.
Any suggestions?
rightView.layer.anchorPoint = CGPointMake(1.0, 0.5);
-(void)stage1
{
[UIView animateWithDuration:1.5 animations:^{
rightView.transform = CGAffineTransformMakeTranslation(0,0); //rightView i UIImageView
CATransform3D _3Dt = CATransform3DIdentity;
_3Dt =CATransform3DMakeRotation(3.141f/42.0f,0.0f,-1.0f,0.0f);
_3Dt.m34 = -0.001f;
_3Dt.m14 = -0.0015f;
rightView.layer.transform = _3Dt;
} completion:^(BOOL finished){
if (finished) {
NSLog(#"finished..");
}
}];
}
-(void)Stage2
{
rightView.layer.anchorPoint = CGPointMake(1.0, 0.5); //issue?
rightView.center = CGPointMake(1012, 384);
[UIView animateWithDuration:1.75 animations:^{
CATransform3D rightTransform = rightView.layer.transform;
rightTransform.m34 = 1.0f/500;
rightTransform = CATransform3DRotate(rightTransform, M_PI_2, 0, 1, 0);
rightView.layer.transform = rightTransform;
} completion:^(BOOL finished) {
}];
}
You need to add the "options" to your animate with duration and add options:UIViewAnimationOptionBeginFromCurrentState
Otherwise it starts from the beginning again.
So your stage 2 would look like this:
-(void)Stage2
{
rightView.layer.anchorPoint = CGPointMake(1.0, 0.5); //issue?
rightView.center = CGPointMake(1012, 384);
[UIView animateWithDuration:1.75
delay:0.00
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
CATransform3D rightTransform = rightView.layer.transform;
rightTransform.m34 = 1.0f/500;
rightTransform = CATransform3DRotate(rightTransform, M_PI_2, 0, 1, 0);
rightView.layer.transform = rightTransform;
} completion:^(BOOL finished) {
}];
}

How to move uiview on this trajectory

Can me explane how I can rotate image use anchor point like
https://www.dropbox.com/s/vh3h5cr1mkdbfh3/ex_image2.JPG
on .m
#import <QuartzCore/QuartzCore.h>
on .h
[UIView animateWithDuration:0.7f
delay:0
options:UIViewAnimationOptionCurveEaseOut
animations:^
{
self.center = position;
self.layer.anchorPoint = CGPointMake(-1, 0);
self.transform = CGAffineTransformMakeRotation(-5);
}
completion:^(BOOL completed){
}];
When I use this code I have something like that
https://www.dropbox.com/s/v87abux9dqm4y0p/ex_image1.JPG
When you apply a rotation transform to a layer, the rotation occurs around the anchor point.
So set the layer's anchor point to (0.0, 0.0) first.
self.layer.anchorPoint = CGPointMake(0.0f, 0.0f);
Then you can just rotate the view and the rotation will occur around the anchor point, (0.0, 0.0).
[UIView animateWithDuration:2.0f animations:^{
self.transform = CGAffineTransformMakeRotation(3.1415f);
}];
The code will rotate the view one whole time in the way you have pictured.
You can check out the section titled "Anchor Points Affect Geometric Manipulations" in Apple's "Core Animation Programming Guide" for more information.

CATransform3D Animation Set X Axis

I have a CATransform3D Animation designed to replace the Push animation currently being used in my app. Currently, it rotates as if the X axis were in the centre of the layer/view. However, I want the X axis to be at the edge of the screen so it flips out of the screen. My current code is: -
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
rotationAndPerspectiveTransform.m34 = 1.0 / 500;
rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, 1.57, 0, 1, 0);
self.view.layer.transform = rotationAndPerspectiveTransform;
[UIView commitAnimations];
I'm new to Core Graphics and such, so any pointers, tips, where I'm going wrong will be greatly appreciated!
You should change the anchorPoint of the layer. Use the following piece of code before beginAnimations:context: method.
CGRect frame = self.view.layer.frame;
self.view.layer.anchorPoint = CGPointMake(1.f, 0.5f);
self.view.layer.frame = frame;
This will change the anchorPoint of the layer without changing the layer position. The rotation animation will be done around the axis that passes from the anchor point.

Resources