卡牌动画实现效果,这里是仿照 积目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;
网友评论