From e107924f900b497ed9446cb6b31f2de840450e16 Mon Sep 17 00:00:00 2001 From: Hang Chen Date: Mon, 1 Apr 2013 22:27:09 +0800 Subject: [PATCH 1/8] Feature enhancement Feature enhancement --- GmailLikeLoadingView.h | 8 ++++-- GmailLikeLoadingView.m | 64 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 60 insertions(+), 12 deletions(-) diff --git a/GmailLikeLoadingView.h b/GmailLikeLoadingView.h index 83537ad..b846c97 100644 --- a/GmailLikeLoadingView.h +++ b/GmailLikeLoadingView.h @@ -8,9 +8,11 @@ #import -@interface GmailLikeLoadingView : UIView +@interface GmailLikeLoadingView : UIView { + NSInteger animationCount_; +} -(void)startAnimating; -(void)stopAnimating; -@property (nonatomic) BOOL isAnimating; - +-(void)allStop; +-(BOOL)isAnimating; @end diff --git a/GmailLikeLoadingView.m b/GmailLikeLoadingView.m index 2edc251..5e86a37 100644 --- a/GmailLikeLoadingView.m +++ b/GmailLikeLoadingView.m @@ -36,7 +36,6 @@ -(NSArray*)splitViewToImages:(UIView*)view forFlipState:(kFlipDirectionState)fli @end @implementation GmailLikeLoadingView -@synthesize isAnimating; - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; @@ -66,7 +65,7 @@ - (id)initWithFrame:(CGRect)frame backLayerView.center = self.center; previousFlipState = kFlipStop; flipState = kFlipBottomTop; - isAnimating = NO; + animationCount_ = 0; horizontal = NO; } return self; @@ -196,7 +195,7 @@ -(void)animateView{ CABasicAnimation *topAnim = [CABasicAnimation animationWithKeyPath:@"transform"]; topAnim.beginTime = CACurrentMediaTime(); - topAnim.duration = 0.5; + topAnim.duration = 0.2; topAnim.fromValue = [NSValue valueWithCATransform3D:skewedIdentityTransform]; if (flipState == kFlipBottomTop || flipState == kFlipTopBottom) { topAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DRotate(skewedIdentityTransform, -M_PI_2, x, y, z)]; @@ -310,21 +309,68 @@ -(void)checkFlipDirectionState { } } +-(BOOL)isAnimating { + return animationCount_ > 0; +} + + -(void)stopAnimating{ - flipState = kFlipStopAnimating; - isAnimating = NO; - [self checkFlipDirectionState]; + if(![NSThread isMainThread]) + { + [self performSelectorOnMainThread:@selector(stopAnimating) withObject:nil waitUntilDone:NO]; + return; + } + if(animationCount_==1){ + animationCount_ = 0; + flipState = kFlipStopAnimating; + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(checkFlipDirectionState) object:nil]; + + [self checkFlipDirectionState]; + + } + else { + animationCount_--; + } + } -(void)startAnimating{ - flipState = kFlipBottomTop; - isAnimating = YES; + if(![NSThread isMainThread]) + { + [self performSelectorOnMainThread:@selector(startAnimating) withObject:nil waitUntilDone:NO]; + return; + } + if (animationCount_<1) { + animationCount_ = 1; + flipState = kFlipBottomTop; + [self checkFlipDirectionState]; + } + else { + animationCount_++; + } +} + + +-(void)allStop { + if(![NSThread isMainThread]) + { + [self performSelectorOnMainThread:@selector(allStop) withObject:nil waitUntilDone:NO]; + return; + } + if(![self isAnimating]) + return; + animationCount_ = 0; + flipState = kFlipStopAnimating; + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(checkFlipDirectionState) object:nil]; + [self checkFlipDirectionState]; + } + #pragma mark - CAAnimation delegate callbacks - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag; { - [self checkFlipDirectionState]; + [self performSelectorOnMainThread:@selector(checkFlipDirectionState) withObject:nil waitUntilDone:NO]; } From 72702b59c2c2ef7f35df88d1bd9bb2fd65ce6c25 Mon Sep 17 00:00:00 2001 From: Hang Chen Date: Mon, 1 Apr 2013 22:27:31 +0800 Subject: [PATCH 2/8] Feature enhancement Feature enhancement --- .DS_Store | Bin 12292 -> 12292 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/.DS_Store b/.DS_Store index 4b4fb4ec509fcd0062cd91e47472410607470811..7b60d2be131ebfd204b9dfea18bd784bf8113d5c 100644 GIT binary patch delta 47 zcmZokXi3=cNRVmolF2$kR+Hs~IGO8ybx+n3a%BP143l>Q1=kAkFfj^j-Yw)Q3jneO B5V!yU delta 47 zcmZokXi3=cNRX-CXR?lv)nqv#PG+vVE|ax{Tv>oL!{psS!L>p>ObiD$?-ufu1ps(* B4 Date: Mon, 8 Apr 2013 00:50:59 +0800 Subject: [PATCH 3/8] Fixed the color overlay issue 1.Fixed the color overlay issue 2.Code refine --- .DS_Store | Bin 12292 -> 12292 bytes GmailLikeLoadingView.m | 163 ++++++++++++++++++++++++----------------- 2 files changed, 95 insertions(+), 68 deletions(-) diff --git a/.DS_Store b/.DS_Store index 7b60d2be131ebfd204b9dfea18bd784bf8113d5c..7b0e36ea49da54e4508366521137da9d77734fed 100644 GIT binary patch delta 25 hcmZokXi3=cNRVlN@?;$$tI2Xga~Ksi?-ufu1ptCH2>}2A delta 25 hcmZokXi3=cNRVmolF2$kR+Hs~<}eCu-Yw)Q3jl?}2`~Tv diff --git a/GmailLikeLoadingView.m b/GmailLikeLoadingView.m index 5e86a37..995f67b 100644 --- a/GmailLikeLoadingView.m +++ b/GmailLikeLoadingView.m @@ -8,7 +8,10 @@ #import "GmailLikeLoadingView.h" #import - +#define COLOR_MEDIUM_SEA_GREEN [UIColor colorWithRed:0.0/255.0f green:147.0/255.0f blue:78.0/255.0f alpha:1.0] +#define COLOR_MEDUIM_BLUE [UIColor colorWithRed:20.0/255.0f green:99.0/255.0f blue:233.0/255.0 alpha:1.0] +#define COLOR_ORANGE [UIColor colorWithRed:255.0/255.0f green:199.0/255.0f blue:12.0/255.0f alpha:1.0] +#define COLOR_MEDIUM_RED [UIColor colorWithRed:221.0/255.0f green:0.0/255.0f blue:31.0/255.0 alpha:1.0] typedef enum { kFlipStop = 0, kFlipTopBottom, @@ -31,6 +34,7 @@ @interface GmailLikeLoadingView (){ NSMutableArray *colorsArray; } -(void)animateView; +-(void)arrangeAnimation; -(NSArray*)splitViewToImages:(UIView*)view forFlipState:(kFlipDirectionState)flipDirection; @end @@ -44,7 +48,7 @@ - (id)initWithFrame:(CGRect)frame CGFloat diameter = MIN(self.frame.size.width, self.frame.size.height); - colorsArray = [NSMutableArray arrayWithObjects:[UIColor colorWithRed:0.0/255.0f green:147.0/255.0f blue:78.0/255.0f alpha:1.0],[UIColor colorWithRed:20.0/255.0f green:99.0/255.0f blue:233.0/255.0 alpha:1.0],[UIColor colorWithRed:255.0/255.0f green:199.0/255.0f blue:12.0/255.0f alpha:1.0],[UIColor colorWithRed:221.0/255.0f green:0.0/255.0f blue:31.0/255.0 alpha:1.0], nil]; + colorsArray = [NSMutableArray arrayWithObjects:COLOR_MEDIUM_SEA_GREEN,COLOR_MEDUIM_BLUE,COLOR_ORANGE,COLOR_MEDIUM_RED, nil]; frontLayerView = [[UIView alloc] init]; [frontLayerView setBackgroundColor:[UIColor clearColor]]; @@ -88,22 +92,22 @@ -(NSArray*)splitViewToImages:(UIView*)view forFlipState:(kFlipDirectionState)fli UIImage *top = nil; UIImage *bottom = nil; UIGraphicsBeginImageContextWithOptions(size, view.layer.opaque, 0.f); - {{ - [renderedImage drawAtPoint:CGPointZero]; - - top = UIGraphicsGetImageFromCurrentImageContext(); - }} + + [renderedImage drawAtPoint:CGPointZero]; + + top = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); UIGraphicsBeginImageContextWithOptions(size, view.layer.opaque, 0.f); - {{ - if (flipDirection == kFlipBottomTop || flipDirection == kFlipTopBottom) { - [renderedImage drawAtPoint:CGPointMake(CGPointZero.x, -renderedImage.size.height / 2)]; - }else{ - [renderedImage drawAtPoint:CGPointMake(-renderedImage.size.width / 2,CGPointZero.y)]; - } - bottom = UIGraphicsGetImageFromCurrentImageContext(); - }} + + if (flipDirection == kFlipBottomTop || flipDirection == kFlipTopBottom) { + [renderedImage drawAtPoint:CGPointMake(CGPointZero.x, -renderedImage.size.height / 2)]; + }else{ + [renderedImage drawAtPoint:CGPointMake(-renderedImage.size.width / 2,CGPointZero.y)]; + } + bottom = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); UIImageView *topHalfView = [[UIImageView alloc] initWithImage:top]; @@ -117,13 +121,6 @@ -(NSArray*)splitViewToImages:(UIView*)view forFlipState:(kFlipDirectionState)fli } -- (CGPoint)center:(CGPoint)oldCenter movedFromAnchorPoint:(CGPoint)oldAnchorPoint toAnchorPoint:(CGPoint)newAnchorPoint withFrame:(CGRect)frame; -{ - CGPoint anchorPointDiff = CGPointMake(newAnchorPoint.x - oldAnchorPoint.x, newAnchorPoint.y - oldAnchorPoint.y); - CGPoint newCenter = CGPointMake(oldCenter.x + (anchorPointDiff.x * frame.size.width), - oldCenter.y + (anchorPointDiff.y * frame.size.height)); - return newCenter; -} -(void)animateView{ @@ -132,15 +129,13 @@ -(void)animateView{ firstHalfFrontLayerView = [frontImages objectAtIndex:0]; secondHalfFrontLayerView = [frontImages objectAtIndex:1]; - [firstHalfFrontLayerView setFrame:CGRectMake(0, 0, firstHalfFrontLayerView.frame.size.width, firstHalfFrontLayerView.frame.size.height)]; - firstHalfFrontLayerView.frame = CGRectOffset(firstHalfFrontLayerView.frame, 0, 0); + firstHalfFrontLayerView.frame = firstHalfFrontLayerView.bounds; [self addSubview:firstHalfFrontLayerView]; - secondHalfFrontLayerView.frame = firstHalfFrontLayerView.frame; if (flipState == kFlipBottomTop || flipState == kFlipTopBottom) { - secondHalfFrontLayerView.frame = CGRectOffset(secondHalfFrontLayerView.frame, 0.f, firstHalfFrontLayerView.frame.size.height); + secondHalfFrontLayerView.frame = CGRectOffset(firstHalfFrontLayerView.frame, 0.f, firstHalfFrontLayerView.frame.size.height); }else{ - secondHalfFrontLayerView.frame = CGRectOffset(secondHalfFrontLayerView.frame, firstHalfFrontLayerView.frame.size.width, 0.f); + secondHalfFrontLayerView.frame = CGRectOffset(firstHalfFrontLayerView.frame, firstHalfFrontLayerView.frame.size.width, 0.f); } [self addSubview:secondHalfFrontLayerView]; @@ -159,85 +154,117 @@ -(void)animateView{ secondHalfBackLayerView.frame = secondHalfFrontLayerView.frame; [self insertSubview:secondHalfBackLayerView belowSubview:secondHalfFrontLayerView]; - - CATransform3D skewedIdentityTransform = CATransform3DIdentity; - float zDistance = 1000.000000; - skewedIdentityTransform.m34 = 1.0 / -zDistance; CGPoint newTopViewAnchorPoint; CGPoint newAnchorPointBottomHalf; - float x,y,z; if (flipState == kFlipBottomTop || flipState == kFlipTopBottom) { newTopViewAnchorPoint = CGPointMake(0.5, 1.0); newAnchorPointBottomHalf = CGPointMake(0.5f, 0.f); + }else{ + newTopViewAnchorPoint = CGPointMake(1.0f, 0.5f); + newAnchorPointBottomHalf = CGPointMake(0.f,0.5f); + } + + firstHalfFrontLayerView.layer.anchorPoint = newTopViewAnchorPoint; + + [firstHalfFrontLayerView setCenter:CGPointMake(self.frame.size.width/2, self.frame.size.height/2)]; + + + [[firstHalfFrontLayerView layer] setOpacity:1.0f]; + [[firstHalfFrontLayerView layer] setOpaque:YES]; + + + + secondHalfBackLayerView.layer.anchorPoint = newAnchorPointBottomHalf; + + [secondHalfBackLayerView setCenter:CGPointMake(self.frame.size.width/2, self.frame.size.height/2)]; + + + [[secondHalfBackLayerView layer] setOpacity:1.0f]; + [[secondHalfBackLayerView layer] setOpaque:YES]; + [self arrangeAnimation]; + +} + + +-(void)arrangeAnimation { + CATransform3D skewedIdentityTransform = CATransform3DIdentity; + float zDistance = 1000.000000; + skewedIdentityTransform.m34 = 1.0 / -zDistance; + float x,y,z; + if (flipState == kFlipBottomTop || flipState == kFlipTopBottom) { x = 1.f; y = 0.f; z = 0.f; }else{ - newTopViewAnchorPoint = CGPointMake(1.0f, 0.5f); - newAnchorPointBottomHalf = CGPointMake(0.f,0.5f); x = 0.f; y = 1.f; z = 0.f; } - CGPoint newTopViewCenter = [self center:firstHalfFrontLayerView.center movedFromAnchorPoint:firstHalfFrontLayerView.layer.anchorPoint toAnchorPoint:newTopViewAnchorPoint withFrame:firstHalfFrontLayerView.frame]; - firstHalfFrontLayerView.layer.anchorPoint = newTopViewAnchorPoint; - if (flipState == kFlipBottomTop || flipState == kFlipTopBottom) { - firstHalfFrontLayerView.center = newTopViewCenter; - }else{ - [firstHalfFrontLayerView setCenter:CGPointMake(self.frame.size.width/2, self.frame.size.height/2)]; - } - - [[firstHalfFrontLayerView layer] setOpacity:1.0f]; - [[firstHalfFrontLayerView layer] setOpaque:YES]; - CABasicAnimation *topAnim = [CABasicAnimation animationWithKeyPath:@"transform"]; + CABasicAnimation *topAnim = [CABasicAnimation animationWithKeyPath:@"transform"]; topAnim.beginTime = CACurrentMediaTime(); - topAnim.duration = 0.2; + topAnim.duration = 0.5; topAnim.fromValue = [NSValue valueWithCATransform3D:skewedIdentityTransform]; - if (flipState == kFlipBottomTop || flipState == kFlipTopBottom) { - topAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DRotate(skewedIdentityTransform, -M_PI_2, x, y, z)]; - }else{ - topAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DRotate(skewedIdentityTransform, M_PI_2, x, y, z)]; + + switch (flipState) { + case kFlipBottomTop: + topAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DRotate(skewedIdentityTransform, -M_PI_2, x, y, z)]; + break; + case kFlipTopBottom: + topAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DRotate(skewedIdentityTransform, -M_PI_2, x, y, z)]; + break; + case kFlipLeftRight: + topAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DRotate(skewedIdentityTransform, M_PI_2, x, y, z)]; + break; + case kFlipRightLeft: + topAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DRotate(skewedIdentityTransform, M_PI_2, x, y, z)]; + break; + default: + break; } + topAnim.delegate = self; topAnim.removedOnCompletion = NO; topAnim.fillMode = kCAFillModeForwards; topAnim.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.70 :0.00 :1.00 :1.00]; - [[firstHalfFrontLayerView layer] setOpacity:0.955555f]; + [[firstHalfFrontLayerView layer] setOpacity:1]; [[firstHalfFrontLayerView layer] setOpaque:YES]; [firstHalfFrontLayerView.layer addAnimation:topAnim forKey:@"topDownFlip"]; - CGPoint newBottomHalfCenter = [self center:secondHalfBackLayerView.center movedFromAnchorPoint:secondHalfBackLayerView.layer.anchorPoint toAnchorPoint:newAnchorPointBottomHalf withFrame:secondHalfBackLayerView.frame]; - secondHalfBackLayerView.layer.anchorPoint = newAnchorPointBottomHalf; - if (flipState == kFlipBottomTop || flipState == kFlipTopBottom) { - secondHalfBackLayerView.center = newBottomHalfCenter; - }else{ - [secondHalfBackLayerView setCenter:CGPointMake(self.frame.size.width/2, self.frame.size.height/2)]; - - } - [[secondHalfBackLayerView layer] setOpacity:1.0f]; - [[secondHalfBackLayerView layer] setOpaque:YES]; - CABasicAnimation *bottomAnim = [CABasicAnimation animationWithKeyPath:@"transform"]; + CABasicAnimation *bottomAnim = [CABasicAnimation animationWithKeyPath:@"transform"]; bottomAnim.beginTime = topAnim.beginTime + topAnim.duration; bottomAnim.duration = topAnim.duration; - if (flipState == kFlipBottomTop || flipState == kFlipTopBottom) { - bottomAnim.fromValue = [NSValue valueWithCATransform3D:CATransform3DRotate(skewedIdentityTransform, M_PI_2, x, y, z)]; - }else{ - bottomAnim.fromValue = [NSValue valueWithCATransform3D:CATransform3DRotate(skewedIdentityTransform, -M_PI_2, x, y, z)]; + + switch (flipState) { + case kFlipBottomTop: + bottomAnim.fromValue = [NSValue valueWithCATransform3D:CATransform3DRotate(skewedIdentityTransform, M_PI_2, x, y, z)]; + break; + case kFlipTopBottom: + bottomAnim.fromValue = [NSValue valueWithCATransform3D:CATransform3DRotate(skewedIdentityTransform, M_PI_2, x, y, z)]; + break; + case kFlipLeftRight: + bottomAnim.fromValue = [NSValue valueWithCATransform3D:CATransform3DRotate(skewedIdentityTransform, -M_PI_2, x, y, z)]; + break; + case kFlipRightLeft: + bottomAnim.fromValue = [NSValue valueWithCATransform3D:CATransform3DRotate(skewedIdentityTransform, -M_PI_2, x, y, z)]; + break; + default: + break; } + bottomAnim.toValue = [NSValue valueWithCATransform3D:skewedIdentityTransform]; bottomAnim.delegate = self; bottomAnim.removedOnCompletion = NO; bottomAnim.fillMode = kCAFillModeBoth; bottomAnim.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.30 :1.00 :1.00 :1.00]; - [[secondHalfBackLayerView layer] setOpacity:0.955555f]; + [[secondHalfBackLayerView layer] setOpacity:1]; [[secondHalfBackLayerView layer] setOpaque:YES]; [secondHalfBackLayerView.layer addAnimation:bottomAnim forKey:@"bottomDownFlip"]; - + } From 55847e7d5dcdef6b439cc624516dd35d62a061ba Mon Sep 17 00:00:00 2001 From: Hang Chen Date: Mon, 8 Apr 2013 01:15:08 +0800 Subject: [PATCH 4/8] Added bottomFirst animation(not finished yet) Added bottomFirst animation(not finished yet) --- GmailLikeLoadingView.m | 103 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 97 insertions(+), 6 deletions(-) diff --git a/GmailLikeLoadingView.m b/GmailLikeLoadingView.m index 995f67b..7bee835 100644 --- a/GmailLikeLoadingView.m +++ b/GmailLikeLoadingView.m @@ -34,7 +34,8 @@ @interface GmailLikeLoadingView (){ NSMutableArray *colorsArray; } -(void)animateView; --(void)arrangeAnimation; +-(void)arrangeTopFirstAnimation; +-(void)arrangeBottomFirstAnimation; -(NSArray*)splitViewToImages:(UIView*)view forFlipState:(kFlipDirectionState)flipDirection; @end @@ -183,27 +184,26 @@ -(void)animateView{ [[secondHalfBackLayerView layer] setOpacity:1.0f]; [[secondHalfBackLayerView layer] setOpaque:YES]; - [self arrangeAnimation]; + [self arrangeTopFirstAnimation]; } - --(void)arrangeAnimation { +-(void)arrangeTopFirstAnimation { CATransform3D skewedIdentityTransform = CATransform3DIdentity; float zDistance = 1000.000000; skewedIdentityTransform.m34 = 1.0 / -zDistance; float x,y,z; if (flipState == kFlipBottomTop || flipState == kFlipTopBottom) { + x = 1.f; y = 0.f; z = 0.f; }else{ + x = 0.f; y = 1.f; z = 0.f; } - - CABasicAnimation *topAnim = [CABasicAnimation animationWithKeyPath:@"transform"]; topAnim.beginTime = CACurrentMediaTime(); topAnim.duration = 0.5; @@ -264,10 +264,101 @@ -(void)arrangeAnimation { [[secondHalfBackLayerView layer] setOpacity:1]; [[secondHalfBackLayerView layer] setOpaque:YES]; [secondHalfBackLayerView.layer addAnimation:bottomAnim forKey:@"bottomDownFlip"]; +} + +-(void)arrangeBottomFirstAnimation { + CATransform3D skewedIdentityTransform = CATransform3DIdentity; + float zDistance = 1000.000000; + skewedIdentityTransform.m34 = 1.0 / -zDistance; + float x,y,z; + if (flipState == kFlipBottomTop || flipState == kFlipTopBottom) { + + x = 1.f; + y = 0.f; + z = 0.f; + }else{ + + x = 0.f; + y = 1.f; + z = 0.f; + } + + + CABasicAnimation *bottomAnim = [CABasicAnimation animationWithKeyPath:@"transform"]; + bottomAnim.beginTime = CACurrentMediaTime(); + bottomAnim.duration = 0.5; + bottomAnim.fromValue = [NSValue valueWithCATransform3D:skewedIdentityTransform]; + + switch (flipState) { + case kFlipBottomTop: + bottomAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DRotate(skewedIdentityTransform, M_PI_2, x, y, z)]; + break; + case kFlipTopBottom: + bottomAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DRotate(skewedIdentityTransform, M_PI_2, x, y, z)]; + break; + case kFlipLeftRight: + bottomAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DRotate(skewedIdentityTransform, -M_PI_2, x, y, z)]; + break; + case kFlipRightLeft: + bottomAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DRotate(skewedIdentityTransform, -M_PI_2, x, y, z)]; + break; + default: + break; + } + + bottomAnim.delegate = self; + bottomAnim.removedOnCompletion = NO; + bottomAnim.fillMode = kCAFillModeForwards; + + + + bottomAnim.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.70 :0.00 :1.00 :1.00]; + [[secondHalfBackLayerView layer] setOpacity:1]; + [[secondHalfBackLayerView layer] setOpaque:YES]; + [secondHalfBackLayerView.layer addAnimation:bottomAnim forKey:@"bottomDownFlip"]; + + + + + + CABasicAnimation *topAnim = [CABasicAnimation animationWithKeyPath:@"transform"]; + topAnim.beginTime = bottomAnim.beginTime + bottomAnim.duration; + topAnim.duration = bottomAnim.duration; + topAnim.toValue = [NSValue valueWithCATransform3D:skewedIdentityTransform]; + + switch (flipState) { + case kFlipBottomTop: + topAnim.fromValue = [NSValue valueWithCATransform3D:CATransform3DRotate(skewedIdentityTransform, -M_PI_2, x, y, z)]; + break; + case kFlipTopBottom: + topAnim.fromValue = [NSValue valueWithCATransform3D:CATransform3DRotate(skewedIdentityTransform, -M_PI_2, x, y, z)]; + break; + case kFlipLeftRight: + topAnim.fromValue = [NSValue valueWithCATransform3D:CATransform3DRotate(skewedIdentityTransform, M_PI_2, x, y, z)]; + break; + case kFlipRightLeft: + topAnim.fromValue = [NSValue valueWithCATransform3D:CATransform3DRotate(skewedIdentityTransform, M_PI_2, x, y, z)]; + break; + default: + break; + } + + topAnim.delegate = self; + topAnim.removedOnCompletion = NO; + //topAnim.fillMode = kCAFillModeForwards; + topAnim.fillMode = kCAFillModeBoth; + + topAnim.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.30 :1.00 :1.00 :1.00]; + [[firstHalfFrontLayerView layer] setOpacity:1]; + [[firstHalfFrontLayerView layer] setOpaque:YES]; + [firstHalfFrontLayerView.layer addAnimation:topAnim forKey:@"topDownFlip"]; + + } + -(void)checkFlipDirectionState { switch (flipState) { case kFlipBottomTop: From d8e134dda5950ee8689fbfc01591e5fd57c616e6 Mon Sep 17 00:00:00 2001 From: Hang Chen Date: Mon, 8 Apr 2013 01:22:44 +0800 Subject: [PATCH 5/8] Fixed the bug of bottom first animation Fixed the bug of bottom first animation --- GmailLikeLoadingView.m | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/GmailLikeLoadingView.m b/GmailLikeLoadingView.m index 7bee835..d4d8b7b 100644 --- a/GmailLikeLoadingView.m +++ b/GmailLikeLoadingView.m @@ -125,7 +125,8 @@ -(NSArray*)splitViewToImages:(UIView*)view forFlipState:(kFlipDirectionState)fli -(void)animateView{ - NSArray *frontImages = [self splitViewToImages:frontLayerView forFlipState:flipState]; + //If bottom first animation, use backLayerView, otherwise use frontLayerView + NSArray *frontImages = [self splitViewToImages:backLayerView forFlipState:flipState]; firstHalfFrontLayerView = [frontImages objectAtIndex:0]; @@ -143,7 +144,8 @@ -(void)animateView{ [frontLayerView removeFromSuperview]; - NSArray *backImages = [self splitViewToImages:backLayerView forFlipState:flipState]; + //If bottom first animation, use frontLayerView, otherwise use backLayerView + NSArray *backImages = [self splitViewToImages:frontLayerView forFlipState:flipState]; firstHalfBackLayerView = [backImages objectAtIndex:0]; @@ -184,7 +186,7 @@ -(void)animateView{ [[secondHalfBackLayerView layer] setOpacity:1.0f]; [[secondHalfBackLayerView layer] setOpaque:YES]; - [self arrangeTopFirstAnimation]; + [self arrangeBottomFirstAnimation]; } From 78029707ec4b45da9de9e0545a70adcef2e0d9c4 Mon Sep 17 00:00:00 2001 From: Hang Chen Date: Sat, 20 Apr 2013 01:36:33 +0800 Subject: [PATCH 6/8] Fully implemented the Gmail loading with four different orientations's animation --- .DS_Store | Bin 12292 -> 12292 bytes GmailLikeLoadingView.m | 87 ++++++++++++++++++++++++++++++++--------- 2 files changed, 68 insertions(+), 19 deletions(-) diff --git a/.DS_Store b/.DS_Store index 7b0e36ea49da54e4508366521137da9d77734fed..7f19b20d397113b3d7784943d9158014efbcf3f0 100644 GIT binary patch delta 40 vcmZokXi1ph&&aniU^hP_-)0^G0jAAsgrZp|HcZ&eF7cgZbDwOP5Rd}^7DEm= delta 80 zcmZokXi1ph&nU1lU^hRbz-Ar+0VaXmd>5CL(voBbhO>3Qx)~TI&k?lX&&^Lk7M!dt bWVKmVD2jD6yTo^v&3Pg-nKw_6&E*FGDQ6nG diff --git a/GmailLikeLoadingView.m b/GmailLikeLoadingView.m index d4d8b7b..45f9aba 100644 --- a/GmailLikeLoadingView.m +++ b/GmailLikeLoadingView.m @@ -30,13 +30,13 @@ @interface GmailLikeLoadingView (){ UIView *secondHalfFrontLayerView; UIView *firstHalfBackLayerView; UIView *secondHalfBackLayerView; - BOOL horizontal; NSMutableArray *colorsArray; } -(void)animateView; -(void)arrangeTopFirstAnimation; -(void)arrangeBottomFirstAnimation; -(NSArray*)splitViewToImages:(UIView*)view forFlipState:(kFlipDirectionState)flipDirection; +-(BOOL)isBottomFirstAnimation; @end @@ -71,7 +71,6 @@ - (id)initWithFrame:(CGRect)frame previousFlipState = kFlipStop; flipState = kFlipBottomTop; animationCount_ = 0; - horizontal = NO; } return self; } @@ -124,9 +123,14 @@ -(NSArray*)splitViewToImages:(UIView*)view forFlipState:(kFlipDirectionState)fli -(void)animateView{ - //If bottom first animation, use backLayerView, otherwise use frontLayerView - NSArray *frontImages = [self splitViewToImages:backLayerView forFlipState:flipState]; + NSArray *frontImages = nil; + if ([self isBottomFirstAnimation]) { + frontImages = [self splitViewToImages:backLayerView forFlipState:flipState]; + } + else { + frontImages = [self splitViewToImages:frontLayerView forFlipState:flipState]; + } firstHalfFrontLayerView = [frontImages objectAtIndex:0]; @@ -145,7 +149,13 @@ -(void)animateView{ [frontLayerView removeFromSuperview]; //If bottom first animation, use frontLayerView, otherwise use backLayerView - NSArray *backImages = [self splitViewToImages:frontLayerView forFlipState:flipState]; + NSArray *backImages = nil; + if ([self isBottomFirstAnimation]) { + backImages = [self splitViewToImages:frontLayerView forFlipState:flipState]; + } + else { + backImages = [self splitViewToImages:backLayerView forFlipState:flipState]; + } firstHalfBackLayerView = [backImages objectAtIndex:0]; @@ -186,10 +196,26 @@ -(void)animateView{ [[secondHalfBackLayerView layer] setOpacity:1.0f]; [[secondHalfBackLayerView layer] setOpaque:YES]; - [self arrangeBottomFirstAnimation]; + + if ([self isBottomFirstAnimation]) { + [self arrangeBottomFirstAnimation]; + } + else { + [self arrangeTopFirstAnimation]; + } } +-(BOOL)isBottomFirstAnimation { + if (flipState == kFlipTopBottom || flipState == kFlipLeftRight) { + return NO; + } + else { + return YES; + } +} + + -(void)arrangeTopFirstAnimation { CATransform3D skewedIdentityTransform = CATransform3DIdentity; float zDistance = 1000.000000; @@ -350,6 +376,7 @@ -(void)arrangeBottomFirstAnimation { //topAnim.fillMode = kCAFillModeForwards; topAnim.fillMode = kCAFillModeBoth; + topAnim.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.30 :1.00 :1.00 :1.00]; [[firstHalfFrontLayerView layer] setOpacity:1]; [[firstHalfFrontLayerView layer] setOpaque:YES]; @@ -362,41 +389,47 @@ -(void)arrangeBottomFirstAnimation { -(void)checkFlipDirectionState { + static int i = 0; switch (flipState) { case kFlipBottomTop: { - horizontal = NO; + i = 0; [self animateView]; previousFlipState = kFlipBottomTop; - flipState = kFlipTopBottom; + flipState = kFlipStop; } break; case kFlipTopBottom: { - horizontal = NO; - [secondHalfBackLayerView.superview bringSubviewToFront:secondHalfBackLayerView]; + i = 0; + [self animateView]; previousFlipState = kFlipTopBottom; flipState = kFlipStop; } break; case kFlipLeftRight: { - horizontal = YES; + i = 0; [self animateView]; previousFlipState = kFlipLeftRight; - flipState = kFlipRightLeft; + flipState = kFlipStop; } break; case kFlipRightLeft: { - horizontal = YES; - [secondHalfBackLayerView.superview bringSubviewToFront:secondHalfBackLayerView]; + i = 0; + [self animateView]; previousFlipState = kFlipRightLeft; flipState = kFlipStop; } break; case kFlipStop: { + if (!i) { + i++; + break; + } + i = 0; [firstHalfFrontLayerView removeFromSuperview]; [secondHalfFrontLayerView removeFromSuperview]; [firstHalfBackLayerView removeFromSuperview]; @@ -405,11 +438,27 @@ -(void)checkFlipDirectionState { CGColorRef color = frontLayerView.layer.backgroundColor; frontLayerView.layer.backgroundColor = backLayerView.layer.backgroundColor; backLayerView.layer.backgroundColor = color; - if (horizontal == NO) { - flipState = kFlipLeftRight; - }else{ - flipState = kFlipBottomTop; + + + + switch (previousFlipState) { + case kFlipBottomTop: + flipState = kFlipRightLeft; + break; + case kFlipTopBottom: + flipState = kFlipLeftRight; + break; + case kFlipLeftRight: + flipState = kFlipBottomTop; + break; + case kFlipRightLeft: + flipState = kFlipTopBottom; + break; + default: + break; } + + UIColor *backColor = [colorsArray objectAtIndex:0]; [self moveObjectsInArray]; backLayerView.layer.backgroundColor = backColor.CGColor; @@ -461,7 +510,7 @@ -(void)startAnimating{ } if (animationCount_<1) { animationCount_ = 1; - flipState = kFlipBottomTop; + flipState = kFlipTopBottom; [self checkFlipDirectionState]; } else { From e55249da94ba8fef00d0872be66d657ba444d247 Mon Sep 17 00:00:00 2001 From: Hang Chen Date: Sat, 20 Apr 2013 20:35:27 +0800 Subject: [PATCH 7/8] Code refine. Removed some unnecessary logic --- GmailLikeLoadingView.m | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/GmailLikeLoadingView.m b/GmailLikeLoadingView.m index 45f9aba..5f29e17 100644 --- a/GmailLikeLoadingView.m +++ b/GmailLikeLoadingView.m @@ -145,8 +145,7 @@ -(void)animateView{ } [self addSubview:secondHalfFrontLayerView]; - - [frontLayerView removeFromSuperview]; + //If bottom first animation, use frontLayerView, otherwise use backLayerView NSArray *backImages = nil; @@ -254,7 +253,7 @@ -(void)arrangeTopFirstAnimation { break; } - topAnim.delegate = self; + topAnim.delegate = nil; topAnim.removedOnCompletion = NO; topAnim.fillMode = kCAFillModeForwards; topAnim.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.70 :0.00 :1.00 :1.00]; @@ -334,7 +333,7 @@ -(void)arrangeBottomFirstAnimation { break; } - bottomAnim.delegate = self; + bottomAnim.delegate = nil; bottomAnim.removedOnCompletion = NO; bottomAnim.fillMode = kCAFillModeForwards; @@ -389,11 +388,9 @@ -(void)arrangeBottomFirstAnimation { -(void)checkFlipDirectionState { - static int i = 0; switch (flipState) { case kFlipBottomTop: { - i = 0; [self animateView]; previousFlipState = kFlipBottomTop; flipState = kFlipStop; @@ -401,7 +398,6 @@ -(void)checkFlipDirectionState { break; case kFlipTopBottom: { - i = 0; [self animateView]; previousFlipState = kFlipTopBottom; flipState = kFlipStop; @@ -409,7 +405,6 @@ -(void)checkFlipDirectionState { break; case kFlipLeftRight: { - i = 0; [self animateView]; previousFlipState = kFlipLeftRight; flipState = kFlipStop; @@ -417,7 +412,6 @@ -(void)checkFlipDirectionState { break; case kFlipRightLeft: { - i = 0; [self animateView]; previousFlipState = kFlipRightLeft; flipState = kFlipStop; @@ -425,11 +419,6 @@ -(void)checkFlipDirectionState { break; case kFlipStop: { - if (!i) { - i++; - break; - } - i = 0; [firstHalfFrontLayerView removeFromSuperview]; [secondHalfFrontLayerView removeFromSuperview]; [firstHalfBackLayerView removeFromSuperview]; From 20b46901868736d871e08775512f0cbce6414249 Mon Sep 17 00:00:00 2001 From: Hang Chen Date: Mon, 10 Jun 2013 19:04:37 +0800 Subject: [PATCH 8/8] Fixed the "jummppy" animation for view exchanging --- GmailLikeLoadingView.m | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/GmailLikeLoadingView.m b/GmailLikeLoadingView.m index 5f29e17..bf985ac 100644 --- a/GmailLikeLoadingView.m +++ b/GmailLikeLoadingView.m @@ -255,12 +255,13 @@ -(void)arrangeTopFirstAnimation { topAnim.delegate = nil; topAnim.removedOnCompletion = NO; - topAnim.fillMode = kCAFillModeForwards; + + topAnim.fillMode = kCAFillModeBoth; topAnim.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.70 :0.00 :1.00 :1.00]; [[firstHalfFrontLayerView layer] setOpacity:1]; [[firstHalfFrontLayerView layer] setOpaque:YES]; [firstHalfFrontLayerView.layer addAnimation:topAnim forKey:@"topDownFlip"]; - + [self bringSubviewToFront:firstHalfFrontLayerView]; CABasicAnimation *bottomAnim = [CABasicAnimation animationWithKeyPath:@"transform"]; bottomAnim.beginTime = topAnim.beginTime + topAnim.duration; @@ -291,6 +292,7 @@ -(void)arrangeTopFirstAnimation { [[secondHalfBackLayerView layer] setOpacity:1]; [[secondHalfBackLayerView layer] setOpaque:YES]; [secondHalfBackLayerView.layer addAnimation:bottomAnim forKey:@"bottomDownFlip"]; + [self bringSubviewToFront:secondHalfBackLayerView]; } -(void)arrangeBottomFirstAnimation { @@ -343,7 +345,7 @@ -(void)arrangeBottomFirstAnimation { [[secondHalfBackLayerView layer] setOpacity:1]; [[secondHalfBackLayerView layer] setOpaque:YES]; [secondHalfBackLayerView.layer addAnimation:bottomAnim forKey:@"bottomDownFlip"]; - + [self bringSubviewToFront:secondHalfBackLayerView]; @@ -381,7 +383,8 @@ -(void)arrangeBottomFirstAnimation { [[firstHalfFrontLayerView layer] setOpaque:YES]; [firstHalfFrontLayerView.layer addAnimation:topAnim forKey:@"topDownFlip"]; - + [self bringSubviewToFront:firstHalfFrontLayerView]; + }