Browse files

Fixed 3D perspective, improved rendering speed, added view controller…

… appear/disappear support, other bug fixes
  • Loading branch information...
1 parent ff5be86 commit bc021d19d2ef7e3093a8937e1a4ccc939023ee09 @Dillion committed Jan 16, 2012
View
40 README
@@ -0,0 +1,40 @@
+iOS-Flip-Transform
+
+-----
+
+Summary:
+Animation component for the effect of flipping as in a news/clock ticker, or a page turn.
+
+-----
+Structured around the idea of a data object (i.e. headline in news, number in a clock, page in a book) as an animation frame, comprised of multiple CALayers.
+
+Supports 3 interaction modes:
+Triggered - as in a tap to flip
+Auto - as in a revolving flip that loops through data
+Controlled - as in a pan gesture that moves the flip layer according to touch
+
+Supports different types of content:
+Blank, with background color
+With image (whether from file or screenshot)
+With dynamic text, either composited on background or on image
+
+Supports customizable parameters:
+Sensitivity, gravity, shadow, text positioning, alignment, font etc.
+-----
+
+Basic Usage:
+
+1. Create delegate object -
+AnimationDelegate *animationDelegate = [[AnimationDelegate alloc] initWithSequenceType:kSequenceAuto directionType:kDirectionForward];
+
+2. Create flip view and assign it to animation delegate -
+FlipView *flipView = [[FlipView alloc] initWithAnimationType:kAnimationFlipVertical
+ animationDelegate:animationDelegate
+ frame:CGRectMake(60, 95, 200, 50)];
+animationDelegate.transformView = flipView;
+
+3. Add flip view as subview and customize properties
+
+4. Call [flipView printText: usingImage: backgroundColor: textColor:] to draw each frame (minimum of 2)
+
+5. Call [animationDelegate startAnimation:] to start the animation. For using buttons or pan gesture, look at the animation controller example
View
12 transform.xcodeproj/project.pbxproj
@@ -23,7 +23,7 @@
4DCA549914778FD5009B8741 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4DCA549714778FD5009B8741 /* InfoPlist.strings */; };
4DCA549B14778FD5009B8741 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DCA549A14778FD5009B8741 /* main.m */; };
4DCA549F14778FD5009B8741 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DCA549E14778FD5009B8741 /* AppDelegate.m */; };
- 4DCA54A714779079009B8741 /* RootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DCA54A614779079009B8741 /* RootViewController.m */; };
+ 4DCA54A714779079009B8741 /* AnimationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DCA54A614779079009B8741 /* AnimationViewController.m */; };
4DCA54AC14779189009B8741 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DCA54AB14779189009B8741 /* QuartzCore.framework */; };
/* End PBXBuildFile section */
@@ -52,8 +52,8 @@
4DCA549C14778FD5009B8741 /* transform-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "transform-Prefix.pch"; sourceTree = "<group>"; };
4DCA549D14778FD5009B8741 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
4DCA549E14778FD5009B8741 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
- 4DCA54A514779079009B8741 /* RootViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RootViewController.h; sourceTree = "<group>"; };
- 4DCA54A614779079009B8741 /* RootViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RootViewController.m; sourceTree = "<group>"; };
+ 4DCA54A514779079009B8741 /* AnimationViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnimationViewController.h; sourceTree = "<group>"; };
+ 4DCA54A614779079009B8741 /* AnimationViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AnimationViewController.m; sourceTree = "<group>"; };
4DCA54AB14779189009B8741 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
@@ -119,8 +119,8 @@
isa = PBXGroup;
children = (
4DC1936214BA092300EC5EE7 /* framework */,
- 4DCA54A514779079009B8741 /* RootViewController.h */,
- 4DCA54A614779079009B8741 /* RootViewController.m */,
+ 4DCA54A514779079009B8741 /* AnimationViewController.h */,
+ 4DCA54A614779079009B8741 /* AnimationViewController.m */,
4DCA549D14778FD5009B8741 /* AppDelegate.h */,
4DCA549E14778FD5009B8741 /* AppDelegate.m */,
4DCA549514778FD5009B8741 /* Supporting Files */,
@@ -222,7 +222,7 @@
files = (
4DCA549B14778FD5009B8741 /* main.m in Sources */,
4DCA549F14778FD5009B8741 /* AppDelegate.m in Sources */,
- 4DCA54A714779079009B8741 /* RootViewController.m in Sources */,
+ 4DCA54A714779079009B8741 /* AnimationViewController.m in Sources */,
4DC1936B14BA092300EC5EE7 /* AnimationDelegate.m in Sources */,
4DC1936C14BA092300EC5EE7 /* AnimationFrame.m in Sources */,
4DC1936D14BA092300EC5EE7 /* FlipView.m in Sources */,
View
BIN ...proj/project.xcworkspace/xcuserdata/dilliontan.xcuserdatad/UserInterfaceState.xcuserstate
Binary file not shown.
View
7 transform/RootViewController.h → transform/AnimationViewController.h
@@ -35,14 +35,17 @@
@class FlipView;
@class AnimationDelegate;
-@interface RootViewController : UIViewController <UIGestureRecognizerDelegate> {
+@interface AnimationViewController : UIViewController <UIGestureRecognizerDelegate> {
// use this to choreograph a sequence of animations that you want the user to step through
int step;
//the controller needs a reference to the delegate for control of the animation sequence
AnimationDelegate *animationDelegate;
AnimationDelegate *animationDelegate2;
+
+ BOOL runWhenRestart;
+
}
@property (nonatomic, retain) FlipView *flipView;
@@ -55,6 +58,8 @@
@property (nonatomic, retain) UIView *panRegion;
@property (nonatomic, retain) UIPanGestureRecognizer *panRecognizer;
+- (void)onBackButtonPressed:(UIBarButtonItem *)sender;
+
- (void)panned:(UIPanGestureRecognizer *)recognizer;
// animation delegate will notify the controller when the animation frame has reached a position of rest
View
52 transform/RootViewController.m → transform/AnimationViewController.m
@@ -30,11 +30,11 @@
*/
-#import "RootViewController.h"
+#import "AnimationViewController.h"
#import "FlipView.h"
#import "AnimationDelegate.h"
-@implementation RootViewController
+@implementation AnimationViewController
@synthesize flipView, flipView2;
@synthesize repeatButton, reverseButton, shadowButton;
@@ -87,6 +87,8 @@ - (void)viewDidLoad
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
+
+ self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(onBackButtonPressed:)];
// first flip view is a vertical flip on auto, like a news ticker
animationDelegate = [[AnimationDelegate alloc] initWithSequenceType:kSequenceAuto
@@ -106,8 +108,11 @@ - (void)viewDidLoad
// }
flipView.font = @"Helvetica Neue Bold";
flipView.fontAlignment = @"center";
+ flipView.textOffset = CGPointMake(0.0, 2.0);
flipView.textTruncationMode = kCATruncationEnd;
+ flipView.sublayerCornerRadius = 6.0f;
+
[flipView printText:@"LOOP" usingImage:nil backgroundColor:[UIColor colorWithRed:0.9 green:0 blue:0 alpha:1] textColor:[UIColor whiteColor]];
[flipView printText:@"A" usingImage:nil backgroundColor:[UIColor colorWithRed:0.75 green:0 blue:0 alpha:1] textColor:[UIColor whiteColor]];
[flipView printText:@"IN" usingImage:nil backgroundColor:[UIColor colorWithRed:0.6 green:0 blue:0 alpha:1] textColor:[UIColor whiteColor]];
@@ -118,6 +123,7 @@ - (void)viewDidLoad
self.repeatButton = [UIButton buttonWithType:UIButtonTypeCustom];
repeatButton.frame = CGRectMake(60, 160, 90, 40);
+ repeatButton.selected = YES;
[repeatButton setBackgroundImage:[UIImage imageNamed:@"repeat_normal"] forState:UIControlStateNormal];
[repeatButton setBackgroundImage:[UIImage imageNamed:@"repeat_selected"] forState:UIControlStateHighlighted];
[repeatButton setBackgroundImage:[UIImage imageNamed:@"repeat_selected"] forState:UIControlStateSelected];
@@ -143,11 +149,11 @@ - (void)viewDidLoad
// screenshot the first flip view
// second flip view is a horizontal flip on controlled, like a book
- UIGraphicsBeginImageContext(CGSizeMake(320, 240));
+ UIGraphicsBeginImageContext(CGSizeMake(260, 150));
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
- CGImageRef imageRef = CGImageCreateWithImageInRect([screenshot CGImage], CGRectMake(0, 40, 320, 200));
+ CGImageRef imageRef = CGImageCreateWithImageInRect([screenshot CGImage], CGRectMake(60, 40, 200, 110));
UIGraphicsEndImageContext();
@@ -160,35 +166,35 @@ - (void)viewDidLoad
self.flipView2 = [[FlipView alloc] initWithAnimationType:kAnimationFlipHorizontal
animationDelegate:animationDelegate2
- frame:CGRectMake(0, 280, 320, 200)];
+ frame:CGRectMake(60, 240, 200, 110)];
animationDelegate2.transformView = flipView2;
[self.view addSubview:flipView2];
flipView2.textInset = CGPointMake(6.0, 0.0);
- flipView2.font = @"Heiti J";
+ flipView2.font = @"AppleGothic";
flipView2.textTruncationMode = kCATruncationEnd;
- flipView2.fontSize = 24;
+ flipView2.fontSize = 18;
flipView2.fontAlignment = @"left";
flipView2.textOffset = CGPointMake(6.0, 16.0);
[flipView2 printText:@"HORIZONTAL\nOR\nVERTICAL FLIPS" usingImage:nil backgroundColor:[UIColor redColor] textColor:[UIColor whiteColor]];
- [flipView2 printText:@"BIDIRECTIONAL\nCUSTOMIZABLE MODES\nAUTO, TRIGGERED,\nCONTROLLED" usingImage:nil backgroundColor:[UIColor redColor] textColor:[UIColor whiteColor]];
+ [flipView2 printText:@"BIDIRECTIONAL\nCUSTOMIZABLE\nAUTO, TRIGGERED,\nCONTROLLED" usingImage:nil backgroundColor:[UIColor redColor] textColor:[UIColor whiteColor]];
[flipView2 printText:@"ADJUSTABLE\nSENSITIVITY\nGRAVITY\nSHADOW" usingImage:nil backgroundColor:[UIColor redColor] textColor:[UIColor whiteColor]];
flipView2.fontAlignment = @"center";
flipView2.textOffset = CGPointMake(6.0, 28.0);
[flipView2 printText:@"SCREENSHOT" usingImage:screenshotAfterCrop backgroundColor:nil textColor:[UIColor redColor]];
- flipView2.fontSize = 40;
+ flipView2.fontSize = 24;
flipView2.fontAlignment = @"left";
flipView2.textOffset = CGPointMake(6.0, 16.0);
[flipView2 printText:@"2.5D\nANIMATIONS" usingImage:nil backgroundColor:[UIColor redColor] textColor:[UIColor whiteColor]];
- self.panRegion = [[UIView alloc] initWithFrame:CGRectMake(0, 280, 320, 200)];
+ self.panRegion = [[UIView alloc] initWithFrame:CGRectMake(60, 240, 200, 110)];
[self.view addSubview:panRegion];
self.panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panned:)];
@@ -198,6 +204,28 @@ - (void)viewDidLoad
[self.view addGestureRecognizer:panRecognizer];
}
+- (void)onBackButtonPressed:(UIBarButtonItem *)sender
+{
+ [self dismissModalViewControllerAnimated:YES];
+}
+
+- (void)viewWillAppear:(BOOL)animated
+{
+ [super viewWillAppear:animated];
+
+ if (animationDelegate.repeat) {
+ [animationDelegate startAnimation:kDirectionNone];
+ }
+}
+
+- (void)viewWillDisappear:(BOOL)animated
+{
+ [super viewWillDisappear:animated];
+
+ [animationDelegate resetTransformValues];
+ [NSObject cancelPreviousPerformRequestsWithTarget:animationDelegate];
+}
+
- (void)toggleRepeat:(UIButton *)sender
{
if (!animationDelegate.repeat) {
@@ -277,7 +305,9 @@ - (void)panned:(UIPanGestureRecognizer *)recognizer
break;
case UIGestureRecognizerStateEnded: {
if (animationDelegate2.animationLock) {
- [animationDelegate2 endState];
+ // provide inertia to panning gesture
+ float value = sqrtf(fabsf([recognizer velocityInView:self.view].x))/10.0f;
+ [animationDelegate2 endStateWithSpeed:value];
}
}
break;
View
8 transform/AppDelegate.h
@@ -1,11 +1,15 @@
#import <UIKit/UIKit.h>
-@class RootViewController;
+@class AnimationViewController;
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
-@property (nonatomic, strong) RootViewController *rootController;
+
+@property (nonatomic, strong) UINavigationController *navigationController;
+@property (nonatomic, strong) AnimationViewController *animationViewController;
+
+- (void)presentAnimationController:(UIButton *)sender;
@end
View
25 transform/AppDelegate.m
@@ -1,11 +1,12 @@
#import "AppDelegate.h"
-#import "RootViewController.h"
+#import "AnimationViewController.h"
@implementation AppDelegate
@synthesize window = _window;
-@synthesize rootController;
+@synthesize navigationController;
+@synthesize animationViewController;
- (void)dealloc
{
@@ -18,14 +19,30 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
- self.rootController = [[RootViewController alloc] init];
- [self.window addSubview:rootController.view];
+ self.window.rootViewController = [[UIViewController alloc] init];
+
+ UIButton *presentAnimationControllerButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
+ presentAnimationControllerButton.frame = CGRectMake(40, 200, 240, 40);
+ [presentAnimationControllerButton setTitle:@"Present Animation Controller" forState:UIControlStateNormal];
+ [presentAnimationControllerButton addTarget:self action:@selector(presentAnimationController:) forControlEvents:UIControlEventTouchUpInside];
+ [self.window.rootViewController.view addSubview:presentAnimationControllerButton];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
+- (void)presentAnimationController:(UIButton *)sender
+{
+ if (!animationViewController) {
+ self.animationViewController = [[AnimationViewController alloc] init];
+ }
+ if (!navigationController) {
+ self.navigationController = [[UINavigationController alloc] initWithRootViewController:animationViewController];
+ }
+ [self.window.rootViewController presentModalViewController:navigationController animated:YES];
+}
+
- (void)applicationWillResignActive:(UIApplication *)application
{
/*
View
2 transform/framework/AnimationDelegate.h
@@ -104,7 +104,7 @@ typedef enum {
// for notifying animation delegate that user input has ended in kSequenceControlled
// and it should move to the nearest resting state
-- (void)endState;
+- (void)endStateWithSpeed:(float)aVelocity;
// reset transform and opacity values
- (void)resetTransformValues;
View
235 transform/framework/AnimationDelegate.m
@@ -71,8 +71,8 @@ - (id)initWithSequenceType:(SequenceType)aType
// default values
nextDuration = 0.6;
repeatDelay = 0.2;
- sensitivity = 10;
- gravity = 3;
+ sensitivity = 40;
+ gravity = 2;
shadow = YES;
if (sequenceType == kSequenceAuto) {
@@ -138,74 +138,7 @@ - (void)animationDidStop:(CABasicAnimation *)theAnimation finished:(BOOL)flag
- (void)animationCallback
{
- AnimationFrame* currentFrame = [transformView.imageStackArray lastObject];
-
- int aX, aY, aZ;
-
- switch (transformView.animationType) {
- case kAnimationFlipVertical:
- aX = 1;
- aY = 0;
- aZ = 0;
- break;
- case kAnimationFlipHorizontal:
- aX = 0;
- aY = 1;
- aZ = 0;
- break;
- default:break;
- }
-
- CALayer *targetLayer;
- CALayer *targetShadowLayer, *targetShadowLayer2;
-
- if (currentDirection == kDirectionForward) {
- targetLayer = [currentFrame.animationImages lastObject];
- } else if (currentDirection == kDirectionBackward) {
- targetLayer = [currentFrame.animationImages objectAtIndex:0];
- }
-
- targetShadowLayer = [targetLayer.sublayers objectAtIndex:1];
- targetShadowLayer2 = [targetLayer.sublayers objectAtIndex:3];
-
- [CATransaction begin];
- [CATransaction setDisableActions:YES];
-
- [targetLayer setValue:[NSValue valueWithCATransform3D:CATransform3DMakeRotation(0, aX, aY, aZ)] forKeyPath:@"transform"];
- targetShadowLayer.opacity = 0.0f;
- targetShadowLayer2.opacity = 0.0f;
-
- for (CALayer *layer in targetLayer.sublayers) {
- [layer removeAllAnimations];
- }
- [targetLayer removeAllAnimations];
-
- targetLayer.zPosition = 0;
-
- CATransform3D aTransform = CATransform3DIdentity;
- targetLayer.sublayerTransform = aTransform;
-
- [CATransaction commit];
-
- if (value != 0.0f) {
- [transformView rearrangeLayers:currentDirection :3];
- } else {
- [transformView rearrangeLayers:currentDirection :2];
- }
-
- if (controller && [controller respondsToSelector:@selector(animationDidFinish:)]) {
- if (currentDirection == kDirectionForward && value == 10.0f) {
- [controller animationDidFinish:1];
- } else if (currentDirection == kDirectionBackward && value == 10.0f) {
- [controller animationDidFinish:-1];
- }
- }
-
- animationState = 0;
- animationLock = NO;
- transitionImageBackup = nil;
- value = 0.0f;
- oldOpacityValue = 0.0f;
+ [self resetTransformValues];
if (repeat && sequenceType == kSequenceAuto) {
// the recommended way to queue CAAnimations by Apple is to offset the beginTime,
@@ -216,67 +149,70 @@ - (void)animationCallback
}
-- (void)endState
+- (void)endStateWithSpeed:(float)aVelocity
{
- AnimationFrame* currentFrame = [transformView.imageStackArray lastObject];
- CALayer *targetLayer;
-
- int aX, aY, aZ;
- int rotationModifier;
-
- switch (transformView.animationType) {
- case kAnimationFlipVertical:
- aX = 1;
- aY = 0;
- aZ = 0;
- rotationModifier = -1;
- break;
- case kAnimationFlipHorizontal:
- aX = 0;
- aY = 1;
- aZ = 0;
- rotationModifier = 1;
- break;
- default:break;
- }
-
- float rotationAfterDirection;
-
- if (currentDirection == kDirectionForward) {
- rotationAfterDirection = M_PI * rotationModifier;
- targetLayer = [currentFrame.animationImages lastObject];
- } else if (currentDirection == kDirectionBackward) {
- rotationAfterDirection = -M_PI * rotationModifier;
- targetLayer = [currentFrame.animationImages objectAtIndex:0];
- }
- CALayer *targetShadowLayer;
-
- [targetLayer setValue:[NSValue valueWithCATransform3D:CATransform3DMakeRotation(rotationAfterDirection/10.0 * value, aX, aY, aZ)] forKeyPath:@"transform"];
- for (CALayer *layer in targetLayer.sublayers) {
- [layer removeAllAnimations];
- }
- [targetLayer removeAllAnimations];
-
if (value == 0.0f) {
- [self animationCallback];
+ [self resetTransformValues];
} else if (value == 10.0f) {
- [self animationCallback];
+ [self resetTransformValues];
} else {
+ AnimationFrame* currentFrame = [transformView.imageStackArray lastObject];
+ CALayer *targetLayer;
+
+ int aX, aY, aZ;
+ int rotationModifier;
+
+ switch (transformView.animationType) {
+ case kAnimationFlipVertical:
+ aX = 1;
+ aY = 0;
+ aZ = 0;
+ rotationModifier = -1;
+ break;
+ case kAnimationFlipHorizontal:
+ aX = 0;
+ aY = 1;
+ aZ = 0;
+ rotationModifier = 1;
+ break;
+ default:break;
+ }
+
+ float rotationAfterDirection;
+
+ if (currentDirection == kDirectionForward) {
+ rotationAfterDirection = M_PI * rotationModifier;
+ targetLayer = [currentFrame.animationImages lastObject];
+ } else if (currentDirection == kDirectionBackward) {
+ rotationAfterDirection = -M_PI * rotationModifier;
+ targetLayer = [currentFrame.animationImages objectAtIndex:0];
+ }
+ CALayer *targetShadowLayer;
+
+ CATransform3D aTransform = CATransform3DIdentity;
+ float zDistance = 850;
+ aTransform.m34 = 1.0 / -zDistance;
+ [targetLayer setValue:[NSValue valueWithCATransform3D:CATransform3DRotate(aTransform,rotationAfterDirection/10.0 * value, aX, aY, aZ)] forKeyPath:@"transform"];
+ for (CALayer *layer in targetLayer.sublayers) {
+ [layer removeAllAnimations];
+ }
+ [targetLayer removeAllAnimations];
+
if (gravity > 0) {
animationState = 1;
- if (value <= 5.0f) {
+ if (value+aVelocity <= 5.0f) {
targetShadowLayer = [targetLayer.sublayers objectAtIndex:1];
[self setTransformProgress:rotationAfterDirection / 10.0 * value
:0.0f
- :1.0f/gravity
+ :1.0f/(gravity+aVelocity)
:aX :aY :aZ
:YES
:NO
@@ -296,7 +232,7 @@ - (void)endState
[self setTransformProgress:rotationAfterDirection / 10.0 * value
:rotationAfterDirection
- :1.0f/gravity
+ :1.0f/(gravity+aVelocity)
:aX :aY :aZ
:YES
:NO
@@ -318,8 +254,58 @@ - (void)endState
- (void)resetTransformValues
{
- oldOpacityValue = 0.0f;
+ AnimationFrame* currentFrame = [transformView.imageStackArray lastObject];
+
+ CALayer *targetLayer;
+ CALayer *targetShadowLayer, *targetShadowLayer2;
+
+ if (currentDirection == kDirectionForward) {
+ targetLayer = [currentFrame.animationImages lastObject];
+ } else if (currentDirection == kDirectionBackward) {
+ targetLayer = [currentFrame.animationImages objectAtIndex:0];
+ }
+
+ targetShadowLayer = [targetLayer.sublayers objectAtIndex:1];
+ targetShadowLayer2 = [targetLayer.sublayers objectAtIndex:3];
+
+ [CATransaction begin];
+ [CATransaction setDisableActions:YES];
+
+ [targetLayer setValue:[NSValue valueWithCATransform3D:CATransform3DIdentity] forKeyPath:@"transform"];
+ targetShadowLayer.opacity = 0.0f;
+ targetShadowLayer2.opacity = 0.0f;
+
+ for (CALayer *layer in targetLayer.sublayers) {
+ [layer removeAllAnimations];
+ }
+ [targetLayer removeAllAnimations];
+
+ targetLayer.zPosition = 0;
+
+ CATransform3D aTransform = CATransform3DIdentity;
+ targetLayer.sublayerTransform = aTransform;
+
+ [CATransaction commit];
+
+ if (value == 10.0f) {
+ [transformView rearrangeLayers:currentDirection :3];
+ } else {
+ [transformView rearrangeLayers:currentDirection :2];
+ }
+
+ if (controller && [controller respondsToSelector:@selector(animationDidFinish:)]) {
+ if (currentDirection == kDirectionForward && value == 10.0f) {
+ [controller animationDidFinish:1];
+ } else if (currentDirection == kDirectionBackward && value == 10.0f) {
+ [controller animationDidFinish:-1];
+ }
+ }
+
+ animationState = 0;
+ animationLock = NO;
+ transitionImageBackup = nil;
value = 0.0f;
+ oldOpacityValue = 0.0f;
}
// set the progress of the animation
@@ -396,7 +382,7 @@ - (void)setTransformValue:(float)aValue delegating:(BOOL)bValue
float adjustedValue;
float opacityValue;
if (sequenceType == kSequenceControlled) {
- adjustedValue = fabs(aValue * (sensitivity/100.0));
+ adjustedValue = fabs(aValue * (sensitivity/1000.0));
} else {
adjustedValue = fabs(aValue);
}
@@ -476,7 +462,10 @@ - (void)setTransformValue:(float)aValue delegating:(BOOL)bValue
[CATransaction begin];
[CATransaction setDisableActions:YES];
- [targetLayer setValue:[NSValue valueWithCATransform3D:CATransform3DMakeRotation(rotationAfterDirection/10.0 * value, aX, aY, aZ)] forKeyPath:@"transform"];
+ CATransform3D aTransform = CATransform3DIdentity;
+ float zDistance = 850;
+ aTransform.m34 = 1.0 / -zDistance;
+ [targetLayer setValue:[NSValue valueWithCATransform3D:CATransform3DRotate(aTransform, rotationAfterDirection/10.0 * value, aX, aY, aZ)] forKeyPath:@"transform"];
targetShadowLayer.opacity = oldOpacityValue;
if (targetShadowLayer2) targetShadowLayer2.opacity = oldOpacityValue;
for (CALayer *layer in targetLayer.sublayers) {
@@ -489,7 +478,7 @@ - (void)setTransformValue:(float)aValue delegating:(BOOL)bValue
if (adjustedValue != value) {
CATransform3D aTransform = CATransform3DIdentity;
- float zDistance = 850;
+ float zDistance = 400;
aTransform.m34 = 1.0 / -zDistance;
targetLayer.sublayerTransform = aTransform;
@@ -557,10 +546,14 @@ - (void)setTransformProgress:(float)startTransformValue
{
//NSLog(@"transform value %f, %f", startTransformValue, endTransformValue);
+ CATransform3D aTransform = CATransform3DIdentity;
+ float zDistance = 850;
+ aTransform.m34 = 1.0 / -zDistance;
+
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform"];
anim.duration = duration;
- anim.fromValue= [NSValue valueWithCATransform3D:CATransform3DMakeRotation(startTransformValue, aX, aY, aZ)];
- anim.toValue=[NSValue valueWithCATransform3D:CATransform3DMakeRotation(endTransformValue, aX, aY, aZ)];
+ anim.fromValue= [NSValue valueWithCATransform3D:CATransform3DRotate(aTransform, startTransformValue, aX, aY, aZ)];
+ anim.toValue=[NSValue valueWithCATransform3D:CATransform3DRotate(aTransform, endTransformValue, aX, aY, aZ)];
if (setDelegate) {
anim.delegate = self;
}
View
2 transform/framework/FlipView.h
@@ -38,6 +38,8 @@
}
+@property (nonatomic) float sublayerCornerRadius;
+
// use this method to add a static overlay layer on top of the animation layers
// set the zPosition to a value higher than all the animation layers
- (void)addOverlay;
View
78 transform/framework/FlipView.m
@@ -37,6 +37,8 @@
@implementation FlipView
+@synthesize sublayerCornerRadius;
+
- (id)initWithAnimationType:(AnimationType)aType
animationDelegate:(AnimationDelegate *)aDelegate
frame:(CGRect)aFrame
@@ -46,6 +48,8 @@ - (id)initWithAnimationType:(AnimationType)aType
animationDelegate:aDelegate
frame:aFrame])) {
+ sublayerCornerRadius = 0.0f;
+
switch (aType) {
case kAnimationFlipVertical:
case kAnimationFlipHorizontal:
@@ -93,29 +97,19 @@ - (BOOL)printText:(NSString *)tickerString
templateWidth,
templateHeight/2);
- CALayer *backLayer = [CALayer layer];
- backLayer.frame = layerRect;
- backLayer.contents = kCAGravityTop;
- backLayer.doubleSided = NO;
+ CALayer *backLayer = [self layerWithFrame:layerRect contentGravity:kCAGravityTop cornerRadius:sublayerCornerRadius doubleSided:NO];
[flipLayer addSublayer:backLayer];
- CALayer *shadowLayer = [CALayer layer];
- shadowLayer.frame = layerRect;
- shadowLayer.doubleSided = NO;
+ CALayer *shadowLayer = [self layerWithFrame:layerRect contentGravity:nil cornerRadius:sublayerCornerRadius doubleSided:YES];
shadowLayer.backgroundColor = [UIColor blackColor].CGColor;
shadowLayer.opacity = 0.0f;
[flipLayer addSublayer:shadowLayer];
- CALayer *frontLayer = [CALayer layer];
- frontLayer.frame = layerRect;
- frontLayer.contentsGravity = kCAGravityBottom;
- frontLayer.doubleSided = NO;
+ CALayer *frontLayer = [self layerWithFrame:layerRect contentGravity:kCAGravityBottom cornerRadius:sublayerCornerRadius doubleSided:NO];
frontLayer.transform = CATransform3DMakeRotation(M_PI, 1.0, 0, 0);
[flipLayer addSublayer:frontLayer];
- CALayer *shadowLayer2 = [CALayer layer];
- shadowLayer2.frame = layerRect;
- shadowLayer2.doubleSided = NO;
+ CALayer *shadowLayer2 = [self layerWithFrame:layerRect contentGravity:nil cornerRadius:sublayerCornerRadius doubleSided:YES];
shadowLayer2.backgroundColor = [UIColor blackColor].CGColor;
shadowLayer2.opacity = 0.0f;
shadowLayer2.transform = CATransform3DMakeRotation(M_PI, 1.0, 0, 0);
@@ -128,31 +122,19 @@ - (BOOL)printText:(NSString *)tickerString
templateHeight/2);
flipLayer2.anchorPoint = CGPointMake(0.5, 0.0);
- CALayer *backLayer2 = [CALayer layer];
- backLayer2.frame = layerRect;
- backLayer2.contents = kCAGravityTop;
- backLayer2.doubleSided = NO;
- backLayer2.masksToBounds = YES;
+ CALayer *backLayer2 = [self layerWithFrame:layerRect contentGravity:kCAGravityTop cornerRadius:sublayerCornerRadius doubleSided:NO];
[flipLayer2 addSublayer:backLayer2];
- CALayer *shadowLayer3 = [CALayer layer];
- shadowLayer3.frame = layerRect;
- shadowLayer3.doubleSided = NO;
+ CALayer *shadowLayer3 = [self layerWithFrame:layerRect contentGravity:nil cornerRadius:sublayerCornerRadius doubleSided:YES];
shadowLayer3.backgroundColor = [UIColor blackColor].CGColor;
shadowLayer3.opacity = 0.0f;
[flipLayer2 addSublayer:shadowLayer3];
- CALayer *frontLayer2 = [CALayer layer];
- frontLayer2.frame = layerRect;
- frontLayer2.contentsGravity = kCAGravityBottom;
- frontLayer2.doubleSided = NO;
- frontLayer2.masksToBounds = YES;
+ CALayer *frontLayer2 = [self layerWithFrame:layerRect contentGravity:kCAGravityBottom cornerRadius:sublayerCornerRadius doubleSided:NO];
frontLayer2.transform = CATransform3DMakeRotation(M_PI, 1.0, 0, 0);
[flipLayer2 addSublayer:frontLayer2];
- CALayer *shadowLayer4 = [CALayer layer];
- shadowLayer4.frame = layerRect;
- shadowLayer4.doubleSided = NO;
+ CALayer *shadowLayer4 = [self layerWithFrame:layerRect contentGravity:nil cornerRadius:sublayerCornerRadius doubleSided:YES];
shadowLayer4.backgroundColor = [UIColor blackColor].CGColor;
shadowLayer4.opacity = 0.0f;
shadowLayer4.transform = CATransform3DMakeRotation(M_PI, 1.0, 0, 0);
@@ -193,29 +175,19 @@ - (BOOL)printText:(NSString *)tickerString
templateWidth/2,
templateHeight);
- CALayer *backLayer = [CALayer layer];
- backLayer.frame = layerRect;
- backLayer.contentsGravity = kCAGravityLeft;
- backLayer.doubleSided = NO;
+ CALayer *backLayer = [self layerWithFrame:layerRect contentGravity:kCAGravityLeft cornerRadius:sublayerCornerRadius doubleSided:NO];
[flipLayer addSublayer:backLayer];
- CALayer *shadowLayer = [CALayer layer];
- shadowLayer.frame = layerRect;
- shadowLayer.doubleSided = NO;
+ CALayer *shadowLayer = [self layerWithFrame:layerRect contentGravity:nil cornerRadius:sublayerCornerRadius doubleSided:YES];
shadowLayer.backgroundColor = [UIColor blackColor].CGColor;
shadowLayer.opacity = 0.0f;
[flipLayer addSublayer:shadowLayer];
- CALayer *frontLayer = [CALayer layer];
- frontLayer.frame = layerRect;
- frontLayer.contentsGravity = kCAGravityRight;
- frontLayer.doubleSided = NO;
+ CALayer *frontLayer = [self layerWithFrame:layerRect contentGravity:kCAGravityRight cornerRadius:sublayerCornerRadius doubleSided:NO];
frontLayer.transform = CATransform3DMakeRotation(M_PI, 0, 1.0, 0);
[flipLayer addSublayer:frontLayer];
- CALayer *shadowLayer2 = [CALayer layer];
- shadowLayer2.frame = layerRect;
- shadowLayer2.doubleSided = NO;
+ CALayer *shadowLayer2 = [self layerWithFrame:layerRect contentGravity:nil cornerRadius:sublayerCornerRadius doubleSided:YES];
shadowLayer2.backgroundColor = [UIColor blackColor].CGColor;
shadowLayer2.opacity = 0.0f;
shadowLayer2.transform = CATransform3DMakeRotation(M_PI, 0, 1.0, 0);
@@ -228,29 +200,19 @@ - (BOOL)printText:(NSString *)tickerString
templateHeight);
flipLayer2.anchorPoint = CGPointMake(0.0, 0.5);
- CALayer *backLayer2 = [CALayer layer];
- backLayer2.frame = layerRect;
- backLayer2.contentsGravity = kCAGravityLeft;
- backLayer2.doubleSided = NO;
+ CALayer *backLayer2 = [self layerWithFrame:layerRect contentGravity:kCAGravityLeft cornerRadius:sublayerCornerRadius doubleSided:NO];
[flipLayer2 addSublayer:backLayer2];
- CALayer *shadowLayer3 = [CALayer layer];
- shadowLayer3.frame = layerRect;
- shadowLayer3.doubleSided = NO;
+ CALayer *shadowLayer3 = [self layerWithFrame:layerRect contentGravity:nil cornerRadius:sublayerCornerRadius doubleSided:YES];
shadowLayer3.backgroundColor = [UIColor blackColor].CGColor;
shadowLayer3.opacity = 0.0f;
[flipLayer2 addSublayer:shadowLayer3];
- CALayer *frontLayer2 = [CALayer layer];
- frontLayer2.frame = layerRect;
- frontLayer2.contentsGravity = kCAGravityRight;
- frontLayer2.doubleSided = NO;
+ CALayer *frontLayer2 = [self layerWithFrame:layerRect contentGravity:kCAGravityRight cornerRadius:sublayerCornerRadius doubleSided:NO];
frontLayer2.transform = CATransform3DMakeRotation(M_PI, 0, 1.0, 0);
[flipLayer2 addSublayer:frontLayer2];
- CALayer *shadowLayer4 = [CALayer layer];
- shadowLayer4.frame = layerRect;
- shadowLayer4.doubleSided = NO;
+ CALayer *shadowLayer4 = [self layerWithFrame:layerRect contentGravity:nil cornerRadius:sublayerCornerRadius doubleSided:YES];
shadowLayer4.backgroundColor = [UIColor blackColor].CGColor;
shadowLayer4.opacity = 0.0f;
shadowLayer4.transform = CATransform3DMakeRotation(M_PI, 0, 1.0, 0);
View
8 transform/framework/GenericAnimationView.h
@@ -66,7 +66,8 @@
@property (nonatomic) CGPoint textOffset;
// font size (different from UILabel font size property)
@property (nonatomic) float fontSize;
-// font
+// provide a font from plist or use inbuilt fonts
+// if the rendering is very slow, change the font
@property (nonatomic, assign) NSString *font;
// font alignment
@property (nonatomic, assign) NSString *fontAlignment;
@@ -86,6 +87,11 @@
backgroundColor:(UIColor *)aBackgroundColor
textColor:(UIColor *)aTextColor;
+- (CALayer *)layerWithFrame:(CGRect)aFrame
+ contentGravity:(NSString *)aContentGravity
+ cornerRadius:(float)aRadius
+ doubleSided:(BOOL)aValue;
+
- (void)rearrangeLayers:(DirectionType)aDirectionType :(int)step;
@end
View
79 transform/framework/GenericAnimationView.m
@@ -88,25 +88,28 @@ - (BOOL)printText:(NSString *)tickerString
backgroundColor:(UIColor *)aBackgroundColor
textColor:(UIColor *)aTextColor {
- // renderInContext requires a new layer
- CALayer *backingLayer = [CALayer layer];
-
- if (aImage) {
- [backingLayer setContents:(id)aImage.CGImage];
- }
-
- if (aBackgroundColor) {
- backingLayer.backgroundColor = aBackgroundColor.CGColor;
- }
-
- backingLayer.frame = CGRectMake(0, 0, templateWidth, templateHeight);
-
- // Composite text onto image layer by rendering a text layer in a new graphics context
- // For dynamic resizing need to compute the bounds based on font ascender and descender, and set the autoresizing mask
- CATextLayer *label = nil;
-
+ // render in context only if there is text
if (tickerString) {
- label = [[CATextLayer alloc] init];
+
+ CALayer *backingLayer = [CALayer layer];
+ // set opaque to improve rendering speed
+ backingLayer.opaque = YES;
+
+ if (aImage) {
+ [backingLayer setContents:(id)aImage.CGImage];
+ }
+
+ if (aBackgroundColor) {
+ backingLayer.backgroundColor = aBackgroundColor.CGColor;
+ }
+
+ backingLayer.frame = CGRectMake(0, 0, templateWidth, templateHeight);
+
+ // Composite text onto image layer by rendering a text layer in a new graphics context
+ // For dynamic resizing need to compute the bounds based on font ascender and descender, and set the autoresizing mask
+ CATextLayer *label = [CATextLayer layer];
+ // for crisp text, set text layer to screen resolution
+ label.contentsScale = [[UIScreen mainScreen] scale];
label.string = tickerString;
label.font = font;
label.fontSize = fontSize;
@@ -122,18 +125,18 @@ - (BOOL)printText:(NSString *)tickerString
label.position = CGPointMake(backingLayer.position.x + textOffset.x, backingLayer.position.y + textOffset.y);
[backingLayer addSublayer:label];
- }
-
- UIGraphicsBeginImageContext(backingLayer.frame.size);
-
- [backingLayer renderInContext:UIGraphicsGetCurrentContext()];
- templateImage = UIGraphicsGetImageFromCurrentImageContext();
-
- UIGraphicsEndImageContext();
-
- if (label) {
+
+ UIGraphicsBeginImageContext(backingLayer.frame.size);
+
+ [backingLayer renderInContext:UIGraphicsGetCurrentContext()];
+ templateImage = UIGraphicsGetImageFromCurrentImageContext();
+
+ UIGraphicsEndImageContext();
+
[label removeFromSuperlayer];
- [label release];
+
+ } else {
+ templateImage = aImage;
}
if (templateImage) {
@@ -143,6 +146,24 @@ - (BOOL)printText:(NSString *)tickerString
return NO;
}
+- (CALayer *)layerWithFrame:(CGRect)aFrame
+ contentGravity:(NSString *)aContentGravity
+ cornerRadius:(float)aRadius
+ doubleSided:(BOOL)aValue
+{
+ CALayer *layer = [CALayer layer];
+ layer.frame = aFrame;
+ if (aContentGravity) {
+ layer.contentsGravity = aContentGravity;
+ }
+ layer.cornerRadius = aRadius;
+ layer.doubleSided = NO;
+ layer.masksToBounds = YES;
+ layer.doubleSided = NO;
+
+ return layer;
+}
+
// Pop the last set of images and push back onto the stack, to prepare for the next animation sequence
- (void)rearrangeLayers:(DirectionType)aDirectionType :(int)step {
// for subclass to implement

0 comments on commit bc021d1

Please sign in to comment.