如何在ios中创建垂直翻转视图动画



我不知道如何垂直翻转我的uiview,我有很多视图,每个视图都是

有一些照片和它们的描述,我想要一个像书一样的翻转视图,但不是

从左到右必须是从上到下或从下到上,

我想像从上到下或从下到上一样垂直翻页,

如何在ios中完成这类工作?

我在谷歌上搜索,但不起作用我是开发的新手

所以请任何人都能正确地指导我如何改变我的观点请帮助我

提前谢谢。

从下载代码https://github.com/mtabini/AFKPageFlipper

并更改AFKPageFlipper.h和AFKPageFlipper.m文件

//
//  AFKPageFlipper.h
//  AFKPageFlipper
//
//  Created by Marco Tabini on 10-10-11.
//  Copyright 2010 AFK Studio Partnership. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>

@class AFKPageFlipper;

@protocol AFKPageFlipperDataSource
- (NSInteger) numberOfPagesForPageFlipper:(AFKPageFlipper *) pageFlipper;
- (UIView *) viewForPage:(NSInteger) page inFlipper:(AFKPageFlipper *) pageFlipper;
@end

typedef enum {
    AFKPageFlipperDirectionTop,
    AFKPageFlipperDirectionBottom,
} AFKPageFlipperDirection;

@interface AFKPageFlipper : UIView {
    NSObject <AFKPageFlipperDataSource> *dataSource;
    NSInteger currentPage;
    NSInteger numberOfPages;
    UIView *currentView;
    UIView *nextView;
    CALayer *backgroundAnimationLayer;
    CALayer *flipAnimationLayer;
    AFKPageFlipperDirection flipDirection;
    float startFlipAngle;
    float endFlipAngle;
    float currentAngle;
    BOOL setNextViewOnCompletion;
    BOOL animating;
    BOOL disabled;
}
@property (nonatomic,retain) NSObject <AFKPageFlipperDataSource> *dataSource;
@property (nonatomic,assign) NSInteger currentPage;
@property (nonatomic, retain) UITapGestureRecognizer *tapRecognizer;
@property (nonatomic, retain) UIPanGestureRecognizer *panRecognizer;
@property (nonatomic,assign) BOOL disabled;
- (void) setCurrentPage:(NSInteger) value animated:(BOOL) animated;
@end



//
//  AFKPageFlipper.m
//  AFKPageFlipper
//
//  Created by Marco Tabini on 10-10-12.
//  Copyright 2010 AFK Studio Partnership. All rights reserved.
//
#import "AFKPageFlipper.h"

#pragma mark -
#pragma mark UIView helpers

@interface UIView(Extended) 
- (UIImage *) imageByRenderingView;
@end

@implementation UIView(Extended)

- (UIImage *) imageByRenderingView {
    CGFloat oldAlpha = self.alpha;
    self.alpha = 1;
    UIGraphicsBeginImageContext(self.bounds.size);
    [self.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    self.alpha = oldAlpha;
    return resultingImage;
}
@end

#pragma mark -
#pragma mark Private interface

@interface AFKPageFlipper()
@property (nonatomic,assign) UIView *currentView;
@property (nonatomic,assign) UIView *nextView;
@end

@implementation AFKPageFlipper
@synthesize tapRecognizer = _tapRecognizer;
@synthesize panRecognizer = _panRecognizer;

#pragma mark -
#pragma mark Flip functionality

- (void) initFlip {
    // Create screenshots of view
    UIImage *currentImage = [self.currentView imageByRenderingView];
    UIImage *newImage = [self.nextView imageByRenderingView];
    // Hide existing views
    self.currentView.alpha = 0;
    self.nextView.alpha = 0;
    // Create representational layers
    CGRect rect = self.bounds;
    rect.size.height /= 2;
    backgroundAnimationLayer = [CALayer layer];
    backgroundAnimationLayer.frame = self.bounds;
    backgroundAnimationLayer.zPosition = -300000;
    CALayer *topLayer = [CALayer layer];
    topLayer.frame = rect;
    topLayer.masksToBounds = YES;
    topLayer.contentsGravity = kCAGravityBottom;
    [backgroundAnimationLayer addSublayer:topLayer];
    rect.origin.y = rect.size.height;
    CALayer *bottomLayer = [CALayer layer];
    bottomLayer.frame = rect;
    bottomLayer.masksToBounds = YES;
    bottomLayer.contentsGravity = kCAGravityTop;
    [backgroundAnimationLayer addSublayer:bottomLayer];
    if (flipDirection == AFKPageFlipperDirectionBottom) {
        topLayer.contents = (id) [newImage CGImage];
        bottomLayer.contents = (id) [currentImage CGImage];
    } else {
        topLayer.contents = (id) [currentImage CGImage];
        bottomLayer.contents = (id) [newImage CGImage];
    }
    [self.layer addSublayer:backgroundAnimationLayer];
    rect.origin.y = 0;
    flipAnimationLayer = [CATransformLayer layer];
    flipAnimationLayer.anchorPoint = CGPointMake(0.5, 1);
    flipAnimationLayer.frame = rect;
    [self.layer addSublayer:flipAnimationLayer];
    CALayer *backLayer = [CALayer layer];
    backLayer.frame = flipAnimationLayer.bounds;
    backLayer.doubleSided = NO;
    backLayer.masksToBounds = YES;
    [flipAnimationLayer addSublayer:backLayer];
    CALayer *frontLayer = [CALayer layer];
    frontLayer.frame = flipAnimationLayer.bounds;
    frontLayer.doubleSided = NO;
    frontLayer.masksToBounds = YES;
    frontLayer.transform = CATransform3DMakeRotation(M_PI, 1.0, 0.0, 0);
    [flipAnimationLayer addSublayer:frontLayer];
    if (flipDirection == AFKPageFlipperDirectionBottom) {
        backLayer.contents = (id) [currentImage CGImage];
        backLayer.contentsGravity = kCAGravityBottom;
        frontLayer.contents = (id) [newImage CGImage];
        frontLayer.contentsGravity = kCAGravityTop;
        CATransform3D transform = CATransform3DMakeRotation(1.1/M_PI, 1.0, 0.0, 0.0);
        transform.m34 = 1.0f / 2500.0f;
        flipAnimationLayer.transform = transform;
        currentAngle = startFlipAngle = 0;
        endFlipAngle = M_PI;
    } else {
        //down
        backLayer.contents = (id) [newImage CGImage];
        backLayer.contentsGravity = kCAGravityBottom;
        frontLayer.contents = (id) [currentImage CGImage];
        frontLayer.contentsGravity = kCAGravityTop;
        CATransform3D transform = CATransform3DMakeRotation(M_PI/1.1, 1.0, 0.0, 0.0);
        transform.m34 = 1.0f / 2500.0f;
        flipAnimationLayer.transform = transform;
        currentAngle = startFlipAngle = M_PI;
        endFlipAngle = 0;
    }
}

- (void) cleanupFlip {
    [backgroundAnimationLayer removeFromSuperlayer];
    [flipAnimationLayer removeFromSuperlayer];
    backgroundAnimationLayer = Nil;
    flipAnimationLayer = Nil;
    animating = NO;
    if (setNextViewOnCompletion) {
        [self.currentView removeFromSuperview];
        self.currentView = self.nextView;
        self.nextView = Nil;
    } else {
        [self.nextView removeFromSuperview];
        self.nextView = Nil;
    }
    self.currentView.alpha = 1;
}

- (void) setFlipProgress:(float) progress setDelegate:(BOOL) setDelegate animate:(BOOL) animate {
    if (animate) {
        animating = YES;
    }
    float newAngle = startFlipAngle + progress * (endFlipAngle - startFlipAngle);
    float duration = animate ? 0.5 * fabs((newAngle - currentAngle) / (endFlipAngle - startFlipAngle)) : 0;
    currentAngle = newAngle;
    CATransform3D endTransform = CATransform3DIdentity;
    endTransform.m34 = 1.0f / 2500.0f;
    endTransform = CATransform3DRotate(endTransform, newAngle, 1.0, 0.0, 0.0);
    [flipAnimationLayer removeAllAnimations];
    [CATransaction begin];
    [CATransaction setAnimationDuration:duration];
    flipAnimationLayer.transform = endTransform;
    [CATransaction commit];
    if (setDelegate) {
        [self performSelector:@selector(cleanupFlip) withObject:Nil afterDelay:duration];
    }
}

- (void) flipPage {
    [self setFlipProgress:1.0 setDelegate:YES animate:YES];
}

#pragma mark -
#pragma mark Animation management

- (void)animationDidStop:(NSString *) animationID finished:(NSNumber *) finished context:(void *) context {
    [self cleanupFlip];
}

#pragma mark -
#pragma mark Properties
@synthesize currentView;

- (void) setCurrentView:(UIView *) value {
    if (currentView) {
        [currentView release];
    }
    currentView = [value retain];
}

@synthesize nextView;

- (void) setNextView:(UIView *) value {
    if (nextView) {
        [nextView release];
    }
    nextView = [value retain];
}

@synthesize currentPage;

- (BOOL) doSetCurrentPage:(NSInteger) value {
    if (value == currentPage) {
        return FALSE;
    }
    flipDirection = value < currentPage ? AFKPageFlipperDirectionBottom : AFKPageFlipperDirectionTop;
    currentPage = value;
    self.nextView = [self.dataSource viewForPage:value inFlipper:self];
    [self addSubview:self.nextView];
    return TRUE;
}   
- (void) setCurrentPage:(NSInteger) value {
    if (![self doSetCurrentPage:value]) {
        return;
    }
    setNextViewOnCompletion = YES;
    animating = YES;
    self.nextView.alpha = 0;
    [UIView beginAnimations:@"" context:Nil];
    [UIView setAnimationDuration:0.5];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
    self.nextView.alpha = 1;
    [UIView commitAnimations];
} 

- (void) setCurrentPage:(NSInteger) value animated:(BOOL) animated {
    if (![self doSetCurrentPage:value]) {
        return;
    }
    setNextViewOnCompletion = YES;
    animating = YES;
    if (animated) {
        [self initFlip];
        [self performSelector:@selector(flipPage) withObject:Nil afterDelay:0.091];
    } else {
        [self animationDidStop:Nil finished:[NSNumber numberWithBool:NO] context:Nil];
    }
}

@synthesize dataSource;

- (void) setDataSource:(NSObject <AFKPageFlipperDataSource>*) value {
    if (dataSource) {
        [dataSource release];
    }
    dataSource = [value retain];
    numberOfPages = [dataSource numberOfPagesForPageFlipper:self];
    currentPage = 0;
    self.currentPage = 1;
}

@synthesize disabled;

- (void) setDisabled:(BOOL) value {
    disabled = value;
    self.userInteractionEnabled = !value;
    for (UIGestureRecognizer *recognizer in self.gestureRecognizers) {
        recognizer.enabled = !value;
    }
}

#pragma mark -
#pragma mark Touch management

- (void) tapped:(UITapGestureRecognizer *) recognizer {
    if (animating || self.disabled) {
        return;
    }
    if (recognizer.state == UIGestureRecognizerStateRecognized) {
        NSInteger newPage;
        if ([recognizer locationInView:self].y < (self.bounds.size.height - self.bounds.origin.y) / 2) {
            newPage = MAX(1, self.currentPage - 1);
        } else {
            newPage = MIN(self.currentPage + 1, numberOfPages);
        }
        [self setCurrentPage:newPage animated:YES];
    }
}

- (void) panned:(UIPanGestureRecognizer *) recognizer {
    if (animating) {
        return;
    }
    static BOOL hasFailed;
    static BOOL initialized;
    static NSInteger oldPage;

    float translation = [recognizer translationInView:self].y;

    float progress = translation / self.bounds.size.height;

    if (flipDirection == AFKPageFlipperDirectionTop) {
        progress = MIN(progress, 0);
    } else {
        progress = MAX(progress, 0);
    }
    switch (recognizer.state) {
        case UIGestureRecognizerStateBegan:
            hasFailed = FALSE;
            initialized = FALSE;
            animating = NO;
            setNextViewOnCompletion = NO;
            break;

        case UIGestureRecognizerStateChanged:
            if (hasFailed) {
                return;
            }
            if (!initialized) {
                oldPage = self.currentPage;
                if (translation > 0) {
                    if (self.currentPage > 1) {
                        [self doSetCurrentPage:self.currentPage - 1];
                    } else {
                        hasFailed = TRUE;
                        return;
                    }
                } else {
                    if (self.currentPage < numberOfPages) {
                        [self doSetCurrentPage:self.currentPage + 1];
                    } else {
                        hasFailed = TRUE;
                        return;
                    }
                }
                hasFailed = NO;
                initialized = TRUE;
                setNextViewOnCompletion = NO;
                [self initFlip];
            }
            [self setFlipProgress:fabs(progress) setDelegate:NO animate:NO];
            break;

        case UIGestureRecognizerStateFailed:
            [self setFlipProgress:0.0 setDelegate:YES animate:YES];
            currentPage = oldPage;
            break;
        case UIGestureRecognizerStateRecognized:
            if (hasFailed) {
                [self setFlipProgress:0.0 setDelegate:YES animate:YES];
                currentPage = oldPage;
                return;
            }
            if (fabs((translation + [recognizer velocityInView:self].y / 4) / self.bounds.size.height) > 0.5) {
                setNextViewOnCompletion = YES;
                [self setFlipProgress:1.0 setDelegate:YES animate:YES];
            } else {
                [self setFlipProgress:0.0 setDelegate:YES animate:YES];
                currentPage = oldPage;
            }
            break;
        default:
            break;
    }
}

#pragma mark -
#pragma mark Frame management

- (void) setFrame:(CGRect) value {
    super.frame = value;
    numberOfPages = [dataSource numberOfPagesForPageFlipper:self];
    if (self.currentPage > numberOfPages) {
        self.currentPage = numberOfPages;
    }
}

#pragma mark -
#pragma mark Initialization and memory management

+ (Class) layerClass {
    return [CATransformLayer class];
}
- (id)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {
        _tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)];
        _panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panned:)];
        [_tapRecognizer requireGestureRecognizerToFail:_panRecognizer];
        [self addGestureRecognizer:_tapRecognizer];
        [self addGestureRecognizer:_panRecognizer];
    }
    return self;
}

- (void)dealloc {
    self.dataSource = Nil;
    self.currentView = Nil;
    self.nextView = Nil;
    self.tapRecognizer = Nil;
    self.panRecognizer = Nil;
    [super dealloc];
}

@end

由于AFKPageFlipper,我能够完成上面的代码。。。。荣誉归于mtabini先生(AFKPageFlipper作者)

您可以设置一个负刻度,如:

[theView setTransform:CGAffineTransformMakeScale(1, -1)];

与Pradeep相同,但有阴影,也适用于ARC:

AFKPageFlipper.h

//
//  AFKPageFlipper.h
//  AFKPageFlipper
//
//  Created by Marco Tabini on 10-10-11.
//  Copyright 2010 AFK Studio Partnership. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>

@class AFKPageFlipper;

@protocol AFKPageFlipperDataSource
- (NSInteger) numberOfPagesForPageFlipper:(AFKPageFlipper *) pageFlipper;
- (UIView *) viewForPage:(NSInteger) page inFlipper:(AFKPageFlipper *) pageFlipper;
@end

typedef enum {
    AFKPageFlipperDirectionTop,
    AFKPageFlipperDirectionBottom,
} AFKPageFlipperDirection;

@interface AFKPageFlipper : UIView {
    NSObject <AFKPageFlipperDataSource> *dataSource;
    NSInteger currentPage;
    NSInteger numberOfPages;
    // shadows
    CALayer *frontLayerShadow;
    CALayer *backLayerShadow;
    CALayer *leftLayerShadow;
    CALayer *rightLayerShadow;
    // shadows
    CALayer *backgroundAnimationLayer;
    CALayer *flipAnimationLayer;

    AFKPageFlipperDirection flipDirection;
    float startFlipAngle;
    float endFlipAngle;
    float currentAngle;
    BOOL setNextViewOnCompletion;
    BOOL animating;
    BOOL disabled;
}
@property (nonatomic,retain) NSObject <AFKPageFlipperDataSource> *dataSource;
@property (nonatomic,assign) NSInteger currentPage;
@property (nonatomic, retain) UITapGestureRecognizer *tapRecognizer;
@property (nonatomic, retain) UIPanGestureRecognizer *panRecognizer;
@property (nonatomic,assign) BOOL disabled;
- (void) setCurrentPage:(NSInteger) value animated:(BOOL) animated;
@end

AFKPageFlipper.m

//
//  AFKPageFlipper.m
//  AFKPageFlipper
//
//  Created by Marco Tabini on 10-10-12.
//  Copyright 2010 AFK Studio Partnership. All rights reserved.
//
#import "AFKPageFlipper.h"

#pragma mark -
#pragma mark UIView helpers

@interface UIView(Extended)
- (UIImage *) imageByRenderingView;
@end

@implementation UIView(Extended)

- (UIImage *) imageByRenderingView {
    CGFloat oldAlpha = self.alpha;
    self.alpha = 1;
    UIGraphicsBeginImageContext(self.bounds.size);
    [self.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    self.alpha = oldAlpha;
    return resultingImage;
}
@end

#pragma mark -
#pragma mark Private interface

@interface AFKPageFlipper()
@property (nonatomic,retain) UIView *currentView;
@property (nonatomic,retain) UIView *nextView;
@end

@implementation AFKPageFlipper
@synthesize tapRecognizer = _tapRecognizer;
@synthesize panRecognizer = _panRecognizer;

#pragma mark -
#pragma mark Flip functionality

- (void) initFlip {
    // Create screenshots of view
    UIImage *currentImage = [self.currentView imageByRenderingView];
    UIImage *newImage = [self.nextView imageByRenderingView];
    // Hide existing views
    self.currentView.alpha = 0;
    self.nextView.alpha = 0;
    // Create representational layers
    CGRect rect = self.bounds;
    rect.size.height /= 2;
    backgroundAnimationLayer = [CALayer layer];
    backgroundAnimationLayer.frame = self.bounds;
    backgroundAnimationLayer.zPosition = -300000;
    CALayer *topLayer = [CALayer layer];
    topLayer.frame = rect;
    topLayer.masksToBounds = YES;
    topLayer.contentsGravity = kCAGravityBottom;
    [backgroundAnimationLayer addSublayer:topLayer];
    rect.origin.y = rect.size.height;
    CALayer *bottomLayer = [CALayer layer];
    bottomLayer.frame = rect;
    bottomLayer.masksToBounds = YES;
    bottomLayer.contentsGravity = kCAGravityTop;
    [backgroundAnimationLayer addSublayer:bottomLayer];
    if (flipDirection == AFKPageFlipperDirectionBottom) {
        topLayer.contents = (id) [newImage CGImage];
        bottomLayer.contents = (id) [currentImage CGImage];
    } else {
        topLayer.contents = (id) [currentImage CGImage];
        bottomLayer.contents = (id) [newImage CGImage];
    }
    [self.layer addSublayer:backgroundAnimationLayer];
    rect.origin.y = 0;
    flipAnimationLayer = [CATransformLayer layer];
    flipAnimationLayer.anchorPoint = CGPointMake(0.5, 1);
    flipAnimationLayer.frame = rect;
    [self.layer addSublayer:flipAnimationLayer];
    CALayer *backLayer = [CALayer layer];
    backLayer.frame = flipAnimationLayer.bounds;
    backLayer.doubleSided = NO;
    backLayer.masksToBounds = YES;
    [flipAnimationLayer addSublayer:backLayer];
    CALayer *frontLayer = [CALayer layer];
    frontLayer.frame = flipAnimationLayer.bounds;
    frontLayer.doubleSided = NO;
    frontLayer.masksToBounds = YES;
    frontLayer.transform = CATransform3DMakeRotation(M_PI, 1.0, 0, 0);
    [flipAnimationLayer addSublayer:frontLayer];
    // shadows
    frontLayerShadow = [CALayer layer];
    frontLayerShadow.frame = frontLayer.bounds;
    frontLayerShadow.doubleSided = NO;
    frontLayerShadow.masksToBounds = YES;
    frontLayerShadow.opacity = 0;
    frontLayerShadow.backgroundColor = [UIColor blackColor].CGColor;
    [frontLayer addSublayer:frontLayerShadow];
    backLayerShadow = [CALayer layer];
    backLayerShadow.frame = backLayer.bounds;
    backLayerShadow.doubleSided = NO;
    backLayerShadow.masksToBounds = YES;
    backLayerShadow.opacity = 0;
    backLayerShadow.backgroundColor = [UIColor blackColor].CGColor;
    [backLayer addSublayer:backLayerShadow];

    leftLayerShadow = [CALayer layer];
    leftLayerShadow.frame = topLayer.bounds;
    leftLayerShadow.doubleSided = NO;
    leftLayerShadow.masksToBounds = YES;
    leftLayerShadow.opacity = 0.0;
    leftLayerShadow.backgroundColor = [UIColor blackColor].CGColor;
    [topLayer addSublayer:leftLayerShadow];
    rightLayerShadow = [CALayer layer];
    rightLayerShadow.frame = bottomLayer.bounds;
    rightLayerShadow.doubleSided = NO;
    rightLayerShadow.masksToBounds = YES;
    rightLayerShadow.opacity = 0.0;
    rightLayerShadow.backgroundColor = [UIColor blackColor].CGColor;
    [bottomLayer addSublayer:rightLayerShadow];
    // shadows

    if (flipDirection == AFKPageFlipperDirectionBottom) {
        backLayer.contents = (id) [currentImage CGImage];
        backLayer.contentsGravity = kCAGravityBottom;
        frontLayer.contents = (id) [newImage CGImage];
        frontLayer.contentsGravity = kCAGravityTop;
        CATransform3D transform = CATransform3DMakeRotation(1.1/M_PI, 1.0, 0.0, 0.0);
        transform.m34 = 1.0f / 2500.0f;
        flipAnimationLayer.transform = transform;
        currentAngle = startFlipAngle = 0;
        endFlipAngle = M_PI;
    } else {
        //down
        backLayer.contents = (id) [newImage CGImage];
        backLayer.contentsGravity = kCAGravityBottom;
        frontLayer.contents = (id) [currentImage CGImage];
        frontLayer.contentsGravity = kCAGravityTop;
        CATransform3D transform = CATransform3DMakeRotation(M_PI/1.1, 1.0, 0.0, 0.0);
        transform.m34 = 1.0f / 2500.0f;
        flipAnimationLayer.transform = transform;
        currentAngle = startFlipAngle = M_PI;
        endFlipAngle = 0;
    }
}

- (void) cleanupFlip {
    [backgroundAnimationLayer removeFromSuperlayer];
    [flipAnimationLayer removeFromSuperlayer];
    backgroundAnimationLayer = Nil;
    flipAnimationLayer = Nil;
    animating = NO;
    if (setNextViewOnCompletion) {
        [self.currentView removeFromSuperview];
        self.currentView = self.nextView;
        self.nextView = Nil;
    } else {
        [self.nextView removeFromSuperview];
        self.nextView = Nil;
    }
    self.currentView.alpha = 1;
}

- (void) setFlipProgress:(float) progress setDelegate:(BOOL) setDelegate animate:(BOOL) animate {
    if (animate) {
        animating = YES;
    }
    float newAngle = startFlipAngle + progress * (endFlipAngle - startFlipAngle);
    float duration = animate ? 0.5 * fabs((newAngle - currentAngle) / (endFlipAngle - startFlipAngle)) : 0;
    currentAngle = newAngle;
    CATransform3D endTransform = CATransform3DIdentity;
    endTransform.m34 = 1.0f / 2500.0f;
    endTransform = CATransform3DRotate(endTransform, newAngle, 1.0, 0.0, 0.0);
    [flipAnimationLayer removeAllAnimations];
    // shadows
    //NSLog(@"End flip angle: %.0f, tstartflip: %.0f, tprogress: %.2ftduration: %.2f", endFlipAngle, startFlipAngle,progress, duration);
    CGFloat newShadowOpacity = (0.5 - progress);
    if(newShadowOpacity < 0) {
        newShadowOpacity *= -1;
    }
    if (newShadowOpacity < 0.05) {
        newShadowOpacity = 0;
    }
    // shadows
    if (duration < 0.15) {
        duration = 0.15;
    }
    [UIView animateWithDuration: duration delay: 0 options: UIViewAnimationOptionCurveLinear animations: ^(void) {
        flipAnimationLayer.transform = endTransform;

        if (endFlipAngle < startFlipAngle) {
            if(progress < 0.5) {
                rightLayerShadow.opacity = newShadowOpacity;
                frontLayerShadow.opacity = (0.5 - newShadowOpacity)/2;
            } else {
                backLayerShadow.opacity = (0.5 - newShadowOpacity)/2;
                leftLayerShadow.opacity = newShadowOpacity;
            }
        } else {
            if(progress < 0.5) {
                leftLayerShadow.opacity = newShadowOpacity;
                backLayerShadow.opacity = (0.5 - newShadowOpacity)/2;

            } else {
                frontLayerShadow.opacity = (0.5 - newShadowOpacity)/2;
                rightLayerShadow.opacity = newShadowOpacity;
            }
        }
        // shadows
    } completion: ^(BOOL completion) {
    }];

    if (setDelegate) {
        [self performSelector:@selector(cleanupFlip) withObject:Nil afterDelay:duration];
    }
}

- (void) flipPage {
    [self setFlipProgress:1.0 setDelegate:YES animate:YES];
}

#pragma mark -
#pragma mark Animation management

- (void)animationDidStop:(NSString *) animationID finished:(NSNumber *) finished context:(void *) context {
    [self cleanupFlip];
}

#pragma mark -
#pragma mark Properties

@synthesize currentPage;

- (BOOL) doSetCurrentPage:(NSInteger) value {
    if (value == currentPage) {
        return FALSE;
    }
    flipDirection = value < currentPage ? AFKPageFlipperDirectionBottom : AFKPageFlipperDirectionTop;
    currentPage = value;
    self.nextView = [self.dataSource viewForPage:value inFlipper:self];
    [self addSubview:self.nextView];
    return TRUE;
}
- (void) setCurrentPage:(NSInteger) value {
    if (![self doSetCurrentPage:value]) {
        return;
    }
    setNextViewOnCompletion = YES;
    animating = YES;
    self.nextView.alpha = 0;
    [UIView beginAnimations:@"" context:Nil];
    [UIView setAnimationDuration:0.5];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
    self.nextView.alpha = 1;
    [UIView commitAnimations];
}

- (void) setCurrentPage:(NSInteger) value animated:(BOOL) animated {
    if (![self doSetCurrentPage:value]) {
        return;
    }
    setNextViewOnCompletion = YES;
    animating = YES;
    if (animated) {
        [self initFlip];
        [self performSelector:@selector(flipPage) withObject:Nil afterDelay:0.091];
    } else {
        [self animationDidStop:Nil finished:[NSNumber numberWithBool:NO] context:Nil];
    }
}

@synthesize dataSource;

- (void) setDataSource:(NSObject <AFKPageFlipperDataSource>*) value {
    if (dataSource) {
        dataSource = nil;
    }
    dataSource = value;
    numberOfPages = [dataSource numberOfPagesForPageFlipper:self];
    currentPage = 0;
    self.currentPage = 1;
}

@synthesize disabled;

- (void) setDisabled:(BOOL) value {
    disabled = value;
    self.userInteractionEnabled = !value;
    for (UIGestureRecognizer *recognizer in self.gestureRecognizers) {
        recognizer.enabled = !value;
    }
}

#pragma mark -
#pragma mark Touch management

- (void) tapped:(UITapGestureRecognizer *) recognizer {
    if (animating || self.disabled) {
        return;
    }
    if (recognizer.state == UIGestureRecognizerStateRecognized) {
        NSInteger newPage;
        if ([recognizer locationInView:self].y < (self.bounds.size.height - self.bounds.origin.y) / 2) {
            newPage = MAX(1, self.currentPage - 1);
        } else {
            newPage = MIN(self.currentPage + 1, numberOfPages);
        }
        [self setCurrentPage:newPage animated:YES];
    }
}

- (void) panned:(UIPanGestureRecognizer *) recognizer {
    if (animating) {
        return;
    }
    static BOOL hasFailed;
    static BOOL initialized;
    static NSInteger oldPage;

    float translation = [recognizer translationInView:self].y;

    float progress = translation / self.bounds.size.height;

    if (flipDirection == AFKPageFlipperDirectionTop) {
        progress = MIN(progress, 0);
    } else {
        progress = MAX(progress, 0);
    }
    switch (recognizer.state) {
        case UIGestureRecognizerStateBegan:
        hasFailed = FALSE;
        initialized = FALSE;
        animating = NO;
        setNextViewOnCompletion = NO;
        break;

        case UIGestureRecognizerStateChanged:
        if (hasFailed) {
            return;
        }
        if (!initialized) {
            oldPage = self.currentPage;
            if (translation > 0) {
                if (self.currentPage > 1) {
                    [self doSetCurrentPage:self.currentPage - 1];
                } else {
                    hasFailed = TRUE;
                    return;
                }
            } else {
                if (self.currentPage < numberOfPages) {
                    [self doSetCurrentPage:self.currentPage + 1];
                } else {
                    hasFailed = TRUE;
                    return;
                }
            }
            hasFailed = NO;
            initialized = TRUE;
            setNextViewOnCompletion = NO;
            [self initFlip];
        }
        [self setFlipProgress:fabs(progress) setDelegate:NO animate:NO];
        break;

        case UIGestureRecognizerStateFailed:
        [self setFlipProgress:0.0 setDelegate:YES animate:YES];
        currentPage = oldPage;
        break;
        case UIGestureRecognizerStateRecognized:
        if (hasFailed) {
            [self setFlipProgress:0.0 setDelegate:YES animate:YES];
            currentPage = oldPage;
            return;
        }
        if (fabs((translation + [recognizer velocityInView:self].y / 4) / self.bounds.size.height) > 0.5) {
            setNextViewOnCompletion = YES;
            [self setFlipProgress:1.0 setDelegate:YES animate:YES];
        } else {
            [self setFlipProgress:0.0 setDelegate:YES animate:YES];
            currentPage = oldPage;
        }
        break;
        default:
        break;
    }
}

#pragma mark -
#pragma mark Frame management
/*
- (void) setFrame:(CGRect) value {
    super.frame = value;
    numberOfPages = [dataSource numberOfPagesForPageFlipper:self];
    if (self.currentPage > numberOfPages) {
        self.currentPage = numberOfPages;
    }
}*/

#pragma mark -
#pragma mark Initialization and memory management

+ (Class) layerClass {
    return [CATransformLayer class];
}
- (id)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {
        [self initRecognizers];
    }
    return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
    if ((self = [super initWithCoder: aDecoder])) {
        [self initRecognizers];
    }
    return self;
}
- (void) initRecognizers {
    _tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)];
    _panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panned:)];
    [_tapRecognizer requireGestureRecognizerToFail:_panRecognizer];
    [self addGestureRecognizer:_tapRecognizer];
    [self addGestureRecognizer:_panRecognizer];
}

@end

最新更新