需求:
20161205170511736.png点击商品列表中正在售卖的商品,通过坐标转换和动画的方式,完成类似点赞动画、加入购物车、查看头像大图等效果。
思路及问题点:
1)点击cell中的的添加+或者减号-来完成加入购物车的动画事件,需要清楚用户点击的是哪一个cell上面的button,更新购物车数量等操作。
__weak typeof(self) this = self;
cell.addGoodBlock = ^(ShopListGoodsCell *cell) {
[this goodAddOrMinusAction:YES cell:cell];
[cell updateCount];
};
cell.minusGoodBlock = ^(ShopListGoodsCell *cell) {
[this goodAddOrMinusAction:NO cell:cell];
[cell updateCount];
};
2)坐标系的转换
将像素point由point所在视图转换到目标视图view中,返回在目标视图view中的像素值
这里我们要将一个位置坐标传出去,但是传什么位置呢?如果是Lable的位置简单的传出去,那么很明显会出现一个问题:不管你点击那个cell的按钮,动画都是从同一个起点出发的,而且绝对不会是任何正确的起点。因为每个cell中Label的位置都是一样的,而我们实际需要的是这个坐标相对于TableView的位置,也就是说它在父视图中的位置,所以这里要将该点坐标转换。
右下角有一组图片和按钮,表示购物车,在tableView中有我们之前传过来的坐标,而我们希望让动画发生在view层级上,所以这里需要两次坐标转换,把右下角的控件集合中的按钮坐标(购物车是个按钮)和tableView中的传过来的起点坐标都转换到self.view中,具体做法是:
if (cell) {
CGRect startRect = [cell convertRect:cell.countLab.frame toView:self.navigationController.view];
[self joinCartAnimationWithRect:startRect];
} else {
CGRect startRect = [self.goodDesView convertRect:self.countLab.frame toView:self.navigationController.view];
[self joinCartAnimationWithRect:startRect];
}
[self updateCount];
3)Bezier曲线的应用
因为我们想产生一种类抛物线的动画,所以这里我们需要二阶Bezier曲线即可,所以要提供三个控制点,起始点和终止点都已经有了,关键就是中间的控制点。在计图实验中生成Bezier时,我们用的一种思路是以直代曲,用大量短线段来表示一条曲线,每一个n阶Bezier曲线(n+1个点)在生成时,总能在n个线段中按照一个比例各找出一个点,而这n个点又能生成一个n-1阶Bezier,我们的Bezier曲线上的点就是当只有一条线段以后按照那个比例找出的那个点。
UIView的动画是作用在layer层级的,所以我们可以生成一个CALayer,在这个layer上添加上自己的图片,然后将动画应用到这个layer中即可。
#pragma mark -加入购物车动画
-(void) joinCartAnimationWithRect:(CGRect)rect
{
//加入购物车结束点
CGFloat endPoint_x = 35;
CGFloat endPoint_y = SCREEN_HEIGHT - 35;
//加入购物车开始点
CGFloat startX = rect.origin.x;
CGFloat startY = rect.origin.y;// 和头部差值
//绘制贝塞尔曲线
UIBezierPath *path= [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(startX, startY)];
//三点曲线 让动画下滑的路线
[path addCurveToPoint:CGPointMake(endPoint_x, endPoint_y)
controlPoint1:CGPointMake(startX, startY)
controlPoint2:CGPointMake(startX - 180, startY - 200)];
CALayer *dotLayer = [CALayer layer];
dotLayer.backgroundColor = [UIColor colorWithRed:244.0/255.0 green:80.0/255.0 blue:100.0/255.0 alpha:1].CGColor;
dotLayer.frame = CGRectMake(0, 0, 16, 16);
dotLayer.cornerRadius = 8;
[self.view.layer addSublayer:dotLayer];
[self groupAnimation:path.CGPath layer:dotLayer];
}
#pragma mark - 组合动画
-(void)groupAnimation:(CGPathRef)path layer:(CALayer*)layer;
{
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
animation.path = path;
animation.rotationMode = kCAAnimationRotateAuto;
CABasicAnimation *alphaAnimation = [CABasicAnimation animationWithKeyPath:@"alpha"];
alphaAnimation.duration = 0.2f;
alphaAnimation.fromValue = [NSNumber numberWithFloat:1.0];
alphaAnimation.toValue = [NSNumber numberWithFloat:0.1];
alphaAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
CAAnimationGroup *groups = [CAAnimationGroup animation];
groups.animations = @[animation,alphaAnimation];
groups.duration = 0.5f;
groups.removedOnCompletion = NO;
groups.fillMode = kCAFillModeForwards;
groups.delegate = self;
[groups setValue:@"groupsAnimation" forKey:@"animationName"];
[layer addAnimation:groups forKey:nil];
[self performSelector:@selector(removeFromLayer:) withObject:layer afterDelay:0.5f];
}
- (void)removeFromLayer:(CALayer *)layerAnimation{
[layerAnimation removeFromSuperlayer];
}
#pragma mark - CAAnimationDelegate
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
//[self performSelector:@selector(removeFromLayer:) withObject:dotLayer afterDelay:0.8f];
if ([[anim valueForKey:@"animationName"]isEqualToString:@"groupsAnimation"]) {
CABasicAnimation *shakeAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
shakeAnimation.duration = 0.25f;
shakeAnimation.fromValue = [NSNumber numberWithFloat:0.9];
shakeAnimation.toValue = [NSNumber numberWithFloat:1];
shakeAnimation.autoreverses = YES;
//这个是下方的自定义View上面放的btn
[self.cardView.cartBtn.layer addAnimation:shakeAnimation forKey:nil];
}
}
网友评论