iOS卡牌动画 卡牌复用

2018-11-13  本文已影响43人  coordinator

卡牌动画实现效果,这里是仿照 积目App 发现陌生人卡牌动画写的动画实现效果,网上找过很多类似的例子,遗憾的是大多数demo都是反复的 new 一个对象,以及 removeFromSuperview。所以这里来写一个复用的两个View来回替换层次实现。

一、动画效果

卡牌动画效果

二、实现原理
原理很简单,在父View上加一个手势,根据手指移动改变在最上层的CardView的Frame。手抬起,最上层的CardView,从屏幕移出去,再放到第二张CardView之下,此时第二张CardView变成第一张,以此类推。

处理手势代码:

- (void)slideCardViewGesture:(UIPanGestureRecognizer *)sender {
    //当前点
    CGPoint touchPoint = [sender locationInView:self];
    //手指在视图上移动的速度(x,y), 正负代表方向,绝对值上|x| > |y| 水平移动, |y|>|x| 竖直移动。
    CGPoint velocity = [sender velocityInView:self];
    
    if (sender.state == UIGestureRecognizerStateBegan) {
        self.toucheUpPoint = touchPoint;
        self.distenceX = 0;
        self.currentFirstCardView = [self getCurrentFirstCardView];
        self.currentSecondCardView = [self getCurrentSecondCardView];
    }
    
    CGFloat percent = [self percentWithCurrent];
    CGRect firstFrame = [self firstCardViewFrame];
    CGRect secondFrame = [self secondCardViewFrame];
    
    //卡牌方向,1:向左 -1:向右
    CGFloat currentDirection = 0;
    if (velocity.x > 0) {
        currentDirection = 1;
    } else {
        currentDirection = -1;
    }
    
    CGFloat distenceX;
    if (self.toucheUpPoint.x > touchPoint.x) {
        distenceX = self.toucheUpPoint.x - touchPoint.x;
    } else {
        distenceX = touchPoint.x - self.toucheUpPoint.x;
    }
    
    CGFloat angle = percent * M_PI/5;

    // 第一个卡牌 随手势移动距离改变位移和旋转
    if (velocity.x > 0) {
        CGAffineTransform locationTransform = CGAffineTransformTranslate(CGAffineTransformIdentity, self.distenceX + distenceX, 0);
        CGAffineTransform rotateTransform = CGAffineTransformRotate(locationTransform, angle);
        self.currentFirstCardView.transform = rotateTransform;
        self.distenceX = self.distenceX + distenceX;
        
    } else {
        CGAffineTransform locationTransform = CGAffineTransformTranslate(CGAffineTransformIdentity, self.distenceX - distenceX, 0);
        CGAffineTransform rotateTransform = CGAffineTransformRotate(locationTransform, angle);
        self.currentFirstCardView.transform = rotateTransform;
        self.distenceX = self.distenceX - distenceX;
    }

    CGFloat xx1 = firstFrame.origin.x - secondFrame.origin.x;
    CGFloat yy1 = firstFrame.origin.y - secondFrame.origin.y;
    CGFloat width1 = firstFrame.size.width - secondFrame.size.width;
    CGFloat height1 = firstFrame.size.height - secondFrame.size.height;
    CGFloat scalePercent = fabs(percent);
    // 第二个卡牌动画
    self.currentSecondCardView.frame = CGRectMake(secondFrame.origin.x + (xx1 * scalePercent),
                                          secondFrame.origin.y + (yy1 * scalePercent),
                                          secondFrame.size.width + (width1 * scalePercent),
                                          secondFrame.size.height + (height1 * scalePercent));

    self.toucheUpPoint = touchPoint;
    
    //手势结束
    //注意:手势结束后,卡牌还在屏幕上,需要手离开屏幕后继续把动画执行完
    if (sender.state == UIGestureRecognizerStateEnded || sender.state == UIGestureRecognizerStateCancelled) {
        //right
        if (velocity.x >= 80 || velocity.x < -80) {
            [self animationViewWithDirection:currentDirection cardAngle:angle timer:0.3];
        } else {
            [self animationViewWithDirection:0 cardAngle:angle timer:0.2];
        }
    }
}

- (void)animationViewWithDirection:(CGFloat)currentDirection cardAngle:(CGFloat)angle timer:(NSTimeInterval)time {
    
    [UIView animateWithDuration:time animations:^{
        if (currentDirection == 0) {
            self.currentFirstCardView.transform = CGAffineTransformIdentity;
            self.currentFirstCardView.frame = [self firstCardViewFrame];
            self.currentSecondCardView.frame = [self secondCardViewFrame];
        } else {
            self.currentSecondCardView.frame = [self firstCardViewFrame];
            self.currentFirstCardView.center = CGPointMake(self.currentFirstCardView.center.x + currentDirection * SCREEN_WIDTH, self.secondCardView.center.y);
        }
    } completion:^(BOOL finished) {
        if (currentDirection != 0) {
            [self sendSubviewToBack:self.currentFirstCardView];
            self.currentFirstCardView.hidden = YES;
            self.currentFirstCardView.transform = CGAffineTransformIdentity;
            [self.currentFirstCardView updateImage];
            
            self.currentFirstCardView.frame = [self secondCardViewFrame];
            self.currentFirstCardView.hidden = NO;
            self.currentFirstCardView.isFront = NO;
            self.currentSecondCardView.isFront = YES;
        } else {
        }
    }];
}

此处说明下注意事项:
第二个卡牌放大到第一个位置,放大过程中图片到frame需要同步适配,使用下面方法解决适配问题。

// 保证图片随着cardView 的 frame 改变而改变
        _cardImgView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

demo地址:https://github.com/jiaohaili/CardsViewAnimation

上一篇下一篇

猜你喜欢

热点阅读