UIImageView layer won't transform more than once - ios

I have an UIImageView that I want to transform inside a callback (specifically: using OpenCV processImage). Inside the callback I calculate an angle at which it should be transformed and set the transform to that angle. It works only the first time, but won't update (I'm logging the angle and have verified that it changes).
However, If I attach a button to the same code I can apply the transform multiple times with no problems. I can also mix the two actions (applying rotate inside the processImage callback and applying rotate on button tap) but rotation only takes affect on the button tap.
Is there some kind of redraw method I'm missing to tell the UIImageView to redraw itself that gets called automatically on button tap?
This actionRotate works fine and applies the rotation every time I tap the button.
- (IBAction)actionRotate:(id)sender {
if (!self.angle) {
self.angle = 0.5f;
} else {
self.angle += 0.1f;
}
CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
rotationAndPerspectiveTransform.m34 = 1.0 / -500;
self.image.layer.transform = CATransform3DRotate(rotationAndPerspectiveTransform, self.angle, 0.0f, 1.0f, 0.0f);
self.image.layer.zPosition = 1000;
NSLog(#"actionRotate angle: %f", self.angle);
}
- (void)viewDidLoad {
[super viewDidLoad];
// init camera
self.videoCamera = [[CvVideoCamera alloc] initWithParentView:self.output];
self.videoCamera.delegate = self;
self.videoCamera.defaultAVCaptureDevicePosition = AVCaptureDevicePositionBack;
self.videoCamera.defaultAVCaptureSessionPreset = AVCaptureSessionPresetMedium;
self.videoCamera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationPortrait;
// 1 fps to slow down log output for debugging
self.videoCamera.defaultFPS = 1;
self.output.frame = CGRectMake(0, 0, 360, 480);
[self.videoCamera start];
}
This processImage does not work. The angle gets incremented correctly, but the transform doesn't get applied. Even if I call [self actionRotate:nil] to be absolutely sure it's the same code running.
- (void)processImage:(Mat&)image;
{
if (!self.angle) {
self.angle = 0.5f;
} else {
self.angle += 0.1f;
}
CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
rotationAndPerspectiveTransform.m34 = 1.0 / -500;
self.image.layer.transform = CATransform3DRotate(rotationAndPerspectiveTransform, self.angle, 0.0f, 1.0f, 0.0f);
self.image.layer.zPosition = 1000;
NSLog(#"processImage angle: %f", self.angle);
}

I discovered that it wasn't running in the main queue, so had to change the code doing the transform in processImage
dispatch_async(dispatch_get_main_queue(), ^{
self.deviation.layer.transform = CATransform3DRotate(rotationAndPerspectiveTransform, self.angle, 0.0f, 1.0f, 0.0f);
self.deviation.layer.zPosition = 1000;
});

Related

Animate Center of Radial Gradient

How can I animate the center of a radial gradient as drawn in a custom CA Layer:
- (instancetype)init
{
self = [super init];
if (self) {
[self setNeedsDisplay];
}
return self;
}
- (void)drawInContext:(CGContextRef)ctx
{
size_t gradLocationsNum = 2;
CGFloat gradLocations[2] = {0.0f, 1.0f};
CGFloat gradColors[8] = {0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.5f};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, gradColors, gradLocations, gradLocationsNum);
CGColorSpaceRelease(colorSpace);
CGPoint gradCenter= CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
float gradRadius = MIN(self.bounds.size.width , self.bounds.size.height) ;
CGContextDrawRadialGradient (ctx, gradient, gradCenter, 0, gradCenter, gradRadius, kCGGradientDrawsAfterEndLocation);
CGGradientRelease(gradient);
}
(from https://stackoverflow.com/a/26924839/668518)
Is there any way to move the center of a radial gradient drawn in this fashion?
You may generate a timer or rather a display link to trigger a refresh method on every frame.
When you start animating you should save the current point to some property (self.animationStartPoint) and save the target point to some property (self.animationEndPoint). Then save the 2 dates you want the animation between like self.animationStartDate = [NSDate date] and self.animationDate = [self.animationStartDate byAddingTimeInterval:animationDuration]. Now when timer or display link fires you need to only call [self setNeedsDisplay].
In draw method you now need to interpolate the two points. First we need to check where in animation time are we:
CGFloat scale = [[NSDate date] timeIntervalSince:self.animationStartDate] / [self.animationEndDate timeIntervalSince:self.animationStartDate];
While animating the scale should be between 0 and 1. If it is less than the animation is still waiting (if you use "after delay" procedure). If it is greater than the animation is over:
if(scale < 0.0) return;
else if(scale > 1.0) {
scale = 1.0;
// TODO: report animation completed, invalidate timer or display link
}
Then use the scale to find the current point:
CGPoint gradCenter = CGPointMake(self.animationStartPoint.x + (self.animationEndPoint.x - self.animationStartPoint.x)*scale, self.animationStartPoint.y + (self.animationEndPoint.y - self.animationStartPoint.y)*scale);

Animated custom layout in UICollectionView

I need to create a UICollectionView like the following picture.
I have been able to make horizontally scrollable, but unable to make the UI like the picture. Any help? Thanks.
Here is what you wanted,you just need to have a custom UICollectionViewFlowLayout,and override the method -(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect to change the cell display attributes.
Here is the layout code with comment in each main operation
#implementation HorizonSclaeLayout
-(instancetype)init{
self = [super init];
if (self) {
self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
}
return self;
}
static const CGFloat kMaxDistancePercentage = 0.3f;
static const CGFloat kMaxRotation = 0;//(CGFloat)(70.0 * (M_PI / 180.0));
static const CGFloat kMaxZoom = 0.6f;
-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
//1 the visible rectangle of the collection view, calculated using the content offset of the view and the bounds size.
CGRect visibleRect = (CGRect){
.origin = self.collectionView.contentOffset,
.size = self.collectionView.bounds.size
};
//2 the maximum distance away from the center, which defines the distance from the center at which each cell is fully rotated
CGFloat maxDistance = visibleRect.size.width/2;
NSArray *array = [super layoutAttributesForElementsInRect:rect];
for (UICollectionViewLayoutAttributes *attributes in array) {
//3 find the distance of the cell from the center of the current visible rectangle
CGFloat distance = CGRectGetMidX(visibleRect) - attributes.center.x;
//4 normalize this distance against the maximum distance to give a percentage of how far the view is along the line from the center to the maximum points in either direction
CGFloat normalizedDistance = distance / maxDistance;
normalizedDistance = MIN(normalizedDistance, 1.0f);
normalizedDistance = MAX(normalizedDistance, -1.0f);
//5 calculate the rotation and zoom
CGFloat rotation = normalizedDistance * kMaxRotation;
CGFloat zoom = 1.0f + ((1.0f - ABS(normalizedDistance))*kMaxZoom);
//6 create the required transform by first setting m34 so that when the rotation is done
// skew is applied to make it have the appearance of coming out of and going into the screen
CATransform3D transform = CATransform3DIdentity;
transform.m34 = - 1.0 / 550.0;
transform = CATransform3DRotate(transform, rotation, 0.0f, 1.0f, 0.0f);
transform = CATransform3DScale(transform, zoom, zoom, 0.0f);
attributes.transform3D = transform;
}
return array;
}
-(CGSize)itemSize{
return CGSizeMake(60, 60 * 1.2);
}
-(CGFloat)minimumLineSpacing{
return 30;
}
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{
return YES;
}
#end
Here in this sample LineLayout has already implemented the required custom layout (that's what I guessed from the image shown).

Animate an arc around centre?

I'm porting some animation code that looks a bit like this:
- (void)drawRect:(CGRect)rect
{
self.angle += 0.1;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 0, 0, 1);
CGContextSetLineWidth(context, 2);
CGContextSetLineCap(context, kCGLineCapButt);
CGContextAddArc(context,
self.frame.size.height/2, self.frame.size.height/2, //center
self.frame.size.height/2 - 2, //radius
0.0 + self.angle, M_PI_4 + self.angle, //arc start/finish
NO);
CGContextStrokePath(context);
}
The problem is that drawRect is only ever called once, when the view is first drawn, so the position of the arc is never updated.
How can I achieve the effect I want (the arc slowly and continuously moving around the centre point)? Most of the animation examples I can find are to perform a one-time animation (such as a fade-In), but not something that is continuous.
I've also tried something along the lines of:
[arcView animateWithDuration:10.0f
delay:1.0f
options: UIViewAnimationOptionRepeat | UIViewAnimationOptionBeginFromCurrentState
animations: ^(void){
_arcView.transform = CGAffineTransformMakeRotation(self.angle++);
}
completion:NULL];
When showing the view, but this doesn't seem to be doing anything either.
A little more about what I'm aiming for: I have a View that I want to be able to set certain states on, e.g. arcView.state = STATE_READY, and for that to change the way it animates. This is being ported from an Android project where it's as simple as adding logic to the draw method on the View, and something reasonably analogous would be preferred.
A couple of observations:
First, drawRect should probably not be incrementing the angle. The purpose of drawRect is to draw a single frame and it should not be changing the state of the view.
If you wanted the UIView subclass to repeated update the angle and redraw itself, you would set up a timer, or better, a CADisplayLink, that will be called periodically, updating the angle and then calling [self setNeedsDisplay] to update the view:
#import "MyView.h"
#interface MyView ()
#property (nonatomic, strong) CADisplayLink *displayLink;
#property (nonatomic) CFTimeInterval startTime;
#property (nonatomic) CGFloat revolutionsPerSecond;
#property (nonatomic) CGFloat angle;
#end
#implementation MyView
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
self.angle = 0.0;
self.revolutionsPerSecond = 0.25; // i.e. go around once per every 4 seconds
[self startDisplayLink];
}
return self;
}
- (void)startDisplayLink
{
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:#selector(handleDisplayLink:)];
self.startTime = CACurrentMediaTime();
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
- (void)stopDisplayLink
{
[self.displayLink invalidate];
self.displayLink = nil;
}
- (void)handleDisplayLink:(CADisplayLink *)displayLink
{
CFTimeInterval elapsed = CACurrentMediaTime() - self.startTime;
double revolutions;
double percent = modf(elapsed * self.revolutionsPerSecond, &revolutions);
self.angle = M_PI * 2.0 * percent;
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 0, 0, 1);
CGContextSetLineWidth(context, 2);
CGContextSetLineCap(context, kCGLineCapButt);
CGContextAddArc(context,
self.frame.size.width/2, self.frame.size.height/2, //center
MIN(self.frame.size.width, self.frame.size.height) / 2.0 - 2.0, //radius
0.0 + self.angle, M_PI_4 + self.angle, //arc start/finish
NO);
CGContextStrokePath(context);
}
#end
An easier approach is to update the transform property of the view, to rotate it. In iOS 7 and later, you add a view with the arc and then rotate it with something like:
[UIView animateKeyframesWithDuration:4.0 delay:0.0 options:UIViewKeyframeAnimationOptionRepeat | UIViewAnimationOptionCurveLinear animations:^{
[UIView addKeyframeWithRelativeStartTime:0.00 relativeDuration:0.25 animations:^{
self.view.transform = CGAffineTransformMakeRotation(M_PI_2);
}];
[UIView addKeyframeWithRelativeStartTime:0.25 relativeDuration:0.25 animations:^{
self.view.transform = CGAffineTransformMakeRotation(M_PI);
}];
[UIView addKeyframeWithRelativeStartTime:0.50 relativeDuration:0.25 animations:^{
self.view.transform = CGAffineTransformMakeRotation(M_PI_2 * 3.0);
}];
[UIView addKeyframeWithRelativeStartTime:0.75 relativeDuration:0.25 animations:^{
self.view.transform = CGAffineTransformMakeRotation(M_PI * 2.0);
}];
} completion:nil];
Note, I've broken the animation up into four steps, because if you rotate from 0 to M_PI * 2.0, it won't animate because it knows the ending point is the same as the starting point. So by breaking it up into four steps like that it does each of the four animations in succession. If doing in in earlier versions of iOS, you do something similar with animateWithDuration, but to have it repeat, you need the completion block to invoke another rotation. Something like: https://stackoverflow.com/a/19408039/1271826
Finally, if you want to animate, for example, just the end of the arc (i.e. to animate the drawing of the arc), you can use CABasicAnimation with a CAShapeLayer:
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.view.bounds.size.width / 2.0, self.view.bounds.size.height / 2.0) radius:MIN(self.view.bounds.size.width, self.view.bounds.size.height) / 2.0 - 2.0 startAngle:0 endAngle:M_PI_4 / 2.0 clockwise:YES];
CAShapeLayer *layer = [CAShapeLayer layer];
layer.frame = self.view.bounds;
layer.path = path.CGPath;
layer.lineWidth = 2.0;
layer.strokeColor = [UIColor redColor].CGColor;
layer.fillColor = [UIColor clearColor].CGColor;
[self.view.layer addSublayer:layer];
CABasicAnimation *animateStrokeEnd = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
animateStrokeEnd.duration = 10.0;
animateStrokeEnd.fromValue = #0.0;
animateStrokeEnd.toValue = #1.0;
animateStrokeEnd.repeatCount = HUGE_VALF;
[layer addAnimation:animateStrokeEnd forKey:#"strokeEndAnimation"];
I know that's probably not what you're looking for, but I mention it just so you can add it to your animation "tool belt".
Most of the animation examples I can find are to perform a one-time
animation (such as a fade-In), but not something that is continuous.
If you use a method like UIView's +animateWithDuration:delay:options:animations:completion: to do your animation, you can specify UIViewAnimationOptionRepeat in the options parameter to make the animation repeat indefinitely.
Fundamentally, using -drawRect: for most animations is the wrong way to go. As you discovered, -drawRect: is only called when the graphics system really needs to redraw the view, and that's a relatively expensive process. As much as possible, you should use Core Animation to do your animations, especially for stuff like this where the view itself doesn't need to be redrawn, but it's pixels need to be transformed somehow.
Note that +animateWithDuration:delay:options:animations:completion: is a class method, so you should send it to UIView itself (or some subclass of UIView), not to an instance of UIView. There's an example here. Also, that particular method might or might not be the best choice for what you're doing -- I just called it out because it's an easy example of using animation with views and it lets you specify the repeating option.
I'm not sure what's wrong with your animation (other than maybe the wrong receiver as described above), but I'd avoid using the ++ operator to modify the angle. The angle is specified in radians, so incrementing by 1 probably isn't what you want. Instead, try adding π/2 to the current rotation, like this:
_arcView.transform = CAAffineTransformRotate(_arcView.transform, M_PI_2);
So this is what I've ended up with. It took a long time to work out the I needed "translation.rotation" instead of just "rotation"...
#implementation arcView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
self.state = 0;
if (self) {
self.layer.contents = (__bridge id)([[self generateArc:[UIColor redColor].CGColor]CGImage]);
}
return self;
}
-(UIImage*)generateArc:(CGColorRef)color{
UIGraphicsBeginImageContext(self.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, color);
CGContextSetLineWidth(context, 2);
CGContextSetLineCap(context, kCGLineCapButt);
CGContextAddArc(context,
self.frame.size.height/2, self.frame.size.height/2,
self.frame.size.height/2 - 2,0.0,M_PI_4,NO);
CGContextStrokePath(context);
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return result;
}
-(void)spin{
[self.layer removeAnimationForKey:#"rotation"];
CABasicAnimation *rotate = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
NSNumber *current =[[self.layer presentationLayer] valueForKeyPath:#"transform.rotation"];
rotate.fromValue = current;
rotate.toValue = [NSNumber numberWithFloat:current.floatValue + M_PI * (self.state*2 - 1)];
rotate.duration = 3.0;
rotate.repeatCount = INT_MAX;
rotate.fillMode = kCAFillModeForwards;
rotate.removedOnCompletion = NO;
[self.layer addAnimation:rotate forKey:#"rotation"];
}

How do i build 3D transform in iOS for ECSlidingViewController?

I want to build a some special animation based https://github.com/ECSlidingViewController/ECSlidingViewController.
The Zoom animation is like below image.
I just want to rotate the main view controller by PI / 4. Like below image.
I had tried to EndState transform like below code, but it doesn't work.
- (void)topViewAnchorRightEndState:(UIView *)topView anchoredFrame:(CGRect)anchoredFrame {
CATransform3D toViewRotationPerspectiveTrans = CATransform3DIdentity;
toViewRotationPerspectiveTrans.m34 = -0.003;
toViewRotationPerspectiveTrans = CATransform3DRotate(toViewRotationPerspectiveTrans, M_PI_4, 0.0f, -1.0f, 0.0f);
topView.layer.transform = toViewRotationPerspectiveTrans;
topView.layer.position = CGPointMake(anchoredFrame.origin.x + ((topView.layer.bounds.size.width * MEZoomAnimationScaleFactor) / 2), topView.layer.position.y);
}
Any help, pointers or example code snippets would be really appreciated!
I managed to do it. From zoom animation code given in ECSlidingViewController, do not apply zoom factor in
- (CGRect)topViewAnchoredRightFrame:(ECSlidingViewController *)slidingViewController{
CGRect frame = slidingViewController.view.bounds;
frame.origin.x = slidingViewController.anchorRightRevealAmount;
frame.size.width = frame.size.width/* * MEZoomAnimationScaleFactor*/;
frame.size.height = frame.size.height/* * MEZoomAnimationScaleFactor*/;
frame.origin.y = (slidingViewController.view.bounds.size.height - frame.size.height) / 2;
return frame;
}
by commenting MEZoomAnimationScaleFactor.
Then at the top of - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext method add
[topView.layer setAnchorPoint:CGPointMake(0, 0.5)];
[topView.layer setZPosition:100];
Finally the method doing all the transformation must be :
- (void)topViewAnchorRightEndState:(UIView *)topView anchoredFrame:(CGRect)anchoredFrame {
CATransform3D transform = CATransform3DIdentity;
transform.m34 = -0.003;
transform = CATransform3DScale(transform, ARDXZoomAnimationScaleFactor, ARDXZoomAnimationScaleFactor, 1);
transform = CATransform3DRotate(transform, -M_PI_4, 0.0, 1.0, 0.0);
topView.layer.transform = transform;
topView.frame = anchoredFrame;
topView.layer.position = CGPointMake(anchoredFrame.origin.x, anchoredFrame.size.height/2+anchoredFrame.origin.y);
}
Enjoy your animation :)
On top of ryancrunchi's answer, you also need to modify the topViewStartingState to reset the x position to 0 and not the middle of the container frame. This removes the jerky offset at the start of the animations:
Change
- (void)topViewStartingState:(UIView *)topView containerFrame:(CGRect)containerFrame {
topView.layer.transform = CATransform3DIdentity;
topView.layer.position = CGPointMake(containerFrame.size.width / 2, containerFrame.size.height / 2);
}
to
- (void)topViewStartingState:(UIView *)topView containerFrame:(CGRect)containerFrame {
topView.layer.transform = CATransform3DIdentity;
topView.layer.position = CGPointMake(0, containerFrame.size.height / 2);
}
There is also a mistake in the animation that causes a jerky left menu at the end of the opening animation. Copy the following line from the completion part of the animation so that it runs during the animation:
[self topViewAnchorRightEndState:topView anchoredFrame:[transitionContext finalFrameForViewController:topViewController]];
The animation function will now look like:
...
if (self.operation == ECSlidingViewControllerOperationAnchorRight) {
[containerView insertSubview:underLeftViewController.view belowSubview:topView];
[topView.layer setAnchorPoint:CGPointMake(0, 0.5)];
[topView.layer setZPosition:100];
[self topViewStartingState:topView containerFrame:containerView.bounds];
[self underLeftViewStartingState:underLeftViewController.view containerFrame:containerView.bounds];
NSTimeInterval duration = [self transitionDuration:transitionContext];
[UIView animateWithDuration:duration animations:^{
[self underLeftViewEndState:underLeftViewController.view];
underLeftViewController.view.frame = [transitionContext finalFrameForViewController:underLeftViewController];
[self topViewAnchorRightEndState:topView anchoredFrame:[transitionContext finalFrameForViewController:topViewController]];
} completion:^(BOOL finished) {
if ([transitionContext transitionWasCancelled]) {
underLeftViewController.view.frame = [transitionContext finalFrameForViewController:underLeftViewController];
underLeftViewController.view.alpha = 1;
[self topViewStartingState:topView containerFrame:containerView.bounds];
}
[transitionContext completeTransition:finished];
}];
}
...

Orienting text on the back of a flipped card?

From a couple of previous StackOverFlow questions and this example on github CA360, I've managed to simulate a flipping card with an image on the "front" and text on the back. However, the text on the back of the card is upside down and I only got it to center horizonatally. How can I orient the text properly and center it vertically on my card?
Card front:
Card back (How to orient and center text vertically?):
[Update]
I set the opacity on my top layer to 0.5 then I got the idea to just "pre-flip" the back layer so that when the actual flip happened that it would just reset it back to normal.
My "pre-flip" looks like this:
cardBack.transform = CATransform3DMakeRotation(M_PI, 1.0f, 0.0f, 0.0f); // Pre-flip card
Now I just need to find a built-in way to vertical setting or do it the hard way... Half the distance...font height... plus...
Set up card container with 2 layers
(Reference):
- (void)loadView {
UIView *myView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
myView.backgroundColor = [UIColor whiteColor];
self.view = myView;
cardContainer = [CATransformLayer layer];
cardContainer.frame = CGRectMake(300, 250, 200, 150);
CALayer *cardFront = [CALayer layer];
cardFront.frame = cardContainer.bounds;
cardFront.zPosition = 5; // Higher than the zPosition of the back of the card
cardFront.contents = (id)[UIImage imageNamed:#"Ben"].CGImage;
cardFront.opacity = 0.5;
[cardContainer addSublayer:cardFront];
/*
https://stackoverflow.com/questions/2209734/add-text-to-calayer
*/
CATextLayer *cardBack = [CATextLayer layer];
cardBack.string = #"Hello";
cardBack.frame = cardContainer.bounds;
cardBack.zPosition = 4;
cardBack.backgroundColor = [[UIColor grayColor] CGColor];
cardBack.alignmentMode = kCAAlignmentCenter;
CFTypeRef *font = (CFTypeRef *)CTFontCreateWithName(CFSTR("Times"), 48, NULL);
cardBack.font = font;
[cardContainer addSublayer: cardBack];
[self.view.layer addSublayer:cardContainer];
}
Code borrowed from another SOF question to flip card:
- (void) flipCard {
// [self.flipTimer invalidate];
// if (flipped){
// return;
// }
NSLog(#"Count=%d", count);
id animationsBlock = ^{
// self.backView.alpha = 1.0f;
// self.frontView.alpha = 0.0f;
// [self bringSubviewToFront:self.frontView];
// flipped = YES;
NSLog(#"Flipping...");
CALayer *layer = cardContainer;
CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
rotationAndPerspectiveTransform.m34 = 1.0 / 500;
if (count == 0) {
rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, M_PI, 1.0f, 0.0f, 0.0f);
} else { // flip it back to image
rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, 0.0f, 0.0f, 1.0f, 1.0f);
}
layer.transform = rotationAndPerspectiveTransform;
};
count = (count + 1) % 2;
[UIView animateWithDuration:1.25
delay:0.0
options: UIViewAnimationCurveEaseInOut
animations:animationsBlock
completion:nil];
}
Are you aware of the UIView class method:
(void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^)(BOOL finished))completion
You would have two views, the front and the back. both can be in your nib. With this call, you can flip from one view to the other view with almost no effort.
EDIT: I did look at your code. Note that anchorPoint, position, and bounds all play together, but you can still use frame. Its interesting (dare I say fun) to play with changing one and seeing how the others change.
What I ended up doing is comment out all setting of position and frame, and essentially set the text box frame as I would with a UIView (width of large view minus width of small view divided by 2,etc):
cardBackText.frame = CGRectMake((200-100)/2, (150-30)/2, 100,30); // 200, 150
NSLog(#"position=%# anchorPoint=%# bounds=%#", NSStringFromCGPoint(cardBackText.position),NSStringFromCGPoint(cardBackText.anchorPoint),NSStringFromCGRect
The log printed this out:
position={100, 75} anchorPoint={0.5, 0.5} bounds={{0, 0}, {100, 30}}

Resources