动画特效二:图片折叠

上一期动画特效,我讲解了《图片翻转》。这一节,我们继续动画之旅,讲解一下图片折叠效果。

图片折叠:顾名思义就是绕着图片的x或者y轴进行折叠,并且看上去有透视效果。先看看最终的效果图:




编程思路分析:

1. 使用一张图片 (Failed) 因为进行图片旋转的时候,如果下半部分的图片往前翻转了,上半部分的图片就会同时往后翻转了。

2. 使用两张图片 (Failed) 通过控制图片的显示与隐藏,但是折叠效果看不出来。

3. 使用一个View(它的大小保持和传递进来的图片大小一致),两张图片,而这两张图片是通过代码裁切,将一张图片裁切为上下两部分,然后分别放置在View的上半部分和下半部分,看起来好像是一张图片(Succeed)。


自定义FoldingView

@interface FoldingView : UIView
- (instancetype)initWithImage:(UIImage *)image;
@end


一、进行初始化工作
- (instancetype)initWithImage:(UIImage *)image {
    if (self = [super init]) {
        self.image = image;
        // 父View的尺寸等于传递过来的图片的尺寸
        self.frame = CGRectMake(0, 0, image.size.width, image.size.height);

        [self addTopView];
        
        [self addBottomView];
        
        [self addGestures];
    }
    return self;
}

二、addTopView用来裁切图片的上半部分并且放置在FoldingView的上面。

- (void)addTopView {
    UIImage *topImage = [self cutImageWithOrignalImage:self.image type:LayerSectionTop];
    
    // 设置图片的frame是父View的frame一半
    self.topImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.bounds), CGRectGetMidY(self.bounds))];
    
    self.topImageView.userInteractionEnabled = YES;
    
    self.topImageView.image = topImage;

    // 设置内容模式为ScaleAspectFit,图片不拉伸
    self.topImageView.contentMode = UIViewContentModeScaleAspectFit;
    
    // 下面设置的position和anchorPoint不写,其实图片已经显示在父控件上面的一半了,但是动画操作的layer是要针对position和anchorPoint的,所以设置他们!!!
    self.topImageView.layer.position = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
    self.topImageView.layer.anchorPoint = CGPointMake(0.5, 1.0);
    
    self.topImageView.layer.mask = [self maskForSection:LayerSectionTop withRect:self.topImageView.bounds];
    
    //self.topImageView.layer.transform = CATransform3DMakePerspective(CGPointZero);
    self.topImageView.layer.transform = [self transform3D];
    [self addSubview:self.topImageView];
}

三、裁切图片的方法: cutImageWithOrignalImage:type方法。为了区分是裁切的上半部分还是下半部分的图片,我定义了一个枚举,用来区别。

typedef NS_ENUM(NSInteger, LayerSection){
    LayerSectionTop,
    LayerSectionBottom
};

// 裁切图片的上面一半或者下面一半
- (UIImage *)cutImageWithOrignalImage:(UIImage *)image type:(LayerSection)section {
    CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height * 0.5);
    if (section == LayerSectionBottom) {
        rect.origin.y = image.size.height * 0.5;
    }
    
    CGImageRef imageRef = CGImageCreateWithImageInRect(image.CGImage, rect);
    UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);
    return finalImage;
}

然后,我们接着看第二点的代码;有两点我需要说明:1.position和anchorPoint的使用(如果想了解具体使用,请参照我以前写的博客position和anchorPoint); 2. 一个View设置部分圆角效果(Core Animation高级理论知识汇总中的专用图层有介绍过)。其实,我们完全可以通过设置被裁切图片的frame来控制图片在FoldingView中的显示位置来达到效果,之所以设置position和anchorPoint就是为了后面的折叠效果做准备。下面一张图说明了折叠原理。

动画特效二:图片折叠_第1张图片

四、添加手势

- (void)addGestures {
    UIPanGestureRecognizer *topPan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panTopEvent:)];
    [self.topImageView addGestureRecognizer:topPan];
}

- (void)panTopEvent:(UIPanGestureRecognizer *)recognizer {
    CGPoint location = [recognizer locationInView:self];
    
    if (recognizer.state == UIGestureRecognizerStateBegan) {
        self.initialLocation = location.y;
        [self bringSubviewToFront:self.topImageView];
    }
    // 上面一半的图片只允许往下拉
    CGFloat delta = location.y - self.initialLocation;
    if (delta < 0) return;
    
    CGFloat conversionFactor = -M_PI / CGRectGetHeight(self.bounds);
    CGFloat angle = delta * conversionFactor;

    if (angle <= -M_PI) {
        angle = -M_PI;
    }
    
    self.topImageView.layer.transform = CATransform3DConcat(CATransform3DMakeRotation(angle, 1, 0, 0), [self transform3D]);

    if (recognizer.state == UIGestureRecognizerStateEnded ||
        recognizer.state == UIGestureRecognizerStateCancelled) {
        [UIView animateWithDuration:0.25 animations:^{
            self.topImageView.layer.transform = [self transform3D];
        } completion:^(BOOL finished) {
            //[self shakeTop];
        }];
    }

}
// 透视效果
- (CATransform3D)transform3D {
    CATransform3D transform = CATransform3DIdentity;
    transform.m34 = kPerspective;
    return transform;
}

关于透视效果有什么不明白的,可以参照CATransform3D 特效详解》。

至此,上半部分图片折叠效果已经实现了,而下半部分很相似,我就不再说明了。

你可能感兴趣的:(动画,animation,animation,core,core,Animation高级)