加入购物车这个动画关键是贝塞尔曲线的绘制,然后给购物车加上一个关键帧动画即可。
贝塞尔曲线的起点从cell 中button开始,到购物车位置结束,控制点取 起点的纵坐标,终点的横坐标。
因为不在一个坐标系内,所以我们需要转换:
- (CGPoint)convertPoint:(CGPoint)point toView:(nullable UIView *)view;
- (CGPoint)convertPoint:(CGPoint)point fromView:(nullable UIView *)view;
- (CGRect)convertRect:(CGRect)rect toView:(nullable UIView *)view;
- (CGRect)convertRect:(CGRect)rect fromView:(nullable UIView *)view;
在这里我们把购物车以及 cell 上的加入购物车按钮 全部转换到selv.view上(ps:本来想把购物车的中心点转化到tableview,上,把动画封装在cell的button 点击事件里,可是失败了, 代理方法会走,但是没有动画效果😢)
cell 中的回调处理
[self layoutIfNeeded];//xib初始化,需要获得正确的frame
CGPoint carButtonCenter = sender.center;
//把button在cell坐标转化为在tableView上的坐标
CGPoint point = [self convertPoint:carButtonCenter toView:self.superview.superview];
//回调
if (_shoppingButtonBlock)
{
_shoppingButtonBlock(point);
}
viewcontroller中的处理
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MyCell *cell =[tableView dequeueReusableCellWithIdentifier:cellId];
if (!cell) {
cell =[[MyCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
}
__weak ViewController *weakSelf = self;
[cell setShoppingButtonBlock:^(CGPoint centerPoint) {
//关键帧动画处理
[weakSelf startAnimate:centerPoint];
}];
return cell;
}
可以把CAShapeLayer去掉,只是为了直观的看到动画效果
-(void)startAnimate:(CGPoint)centerPoint
{
//起点
CGPoint startPoint = [self.tableview convertPoint:centerPoint toView:self.view];;
CGPoint endpoint = self.shopView.center;
//控点
CGPoint controlPoint = CGPointMake(endpoint.x, startPoint.y);
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:startPoint];
[path addQuadCurveToPoint:endpoint controlPoint:controlPoint];
CAShapeLayer *layer =[CAShapeLayer layer];
layer.path = path.CGPath;
layer.fillColor = [UIColor clearColor].CGColor;
layer.strokeColor = [UIColor redColor].CGColor;
layer.lineWidth = 3.0f;
layer.shouldRasterize = YES;//抗锯齿
[self.view.layer addSublayer:layer];
//创建关键帧
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
//动画时间
animation.duration = 1;
animation.path = path.CGPath
;
//当动画完成,停留到结束位置
animation.removedOnCompletion = YES;
animation.fillMode = kCAFillModeForwards;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[self.shopView.layer addAnimation:animation forKey:nil];
path = nil;
}
还是将动画抽取出来,只需要起点和终点以及动画宿主视图,实现解耦。
定义一个NSObject类,接口如下:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface AddToShopAnimation : NSObject
-(instancetype)initWithStartPoint:(CGPoint)startPoint entPoint:(CGPoint)endPoint ViewController:(UIViewController *)viewController HostView:(UIView *)shopView;
-(void)startAnimation;
@end
-(void)startAnimation
{
//起点
//控点
CGPoint controlPoint = CGPointMake(_endPoint.x, _startPoint.y);
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:_startPoint];
[path addQuadCurveToPoint:_endPoint controlPoint:controlPoint];
CAShapeLayer *layer =[CAShapeLayer layer];
layer.path = path.CGPath;
layer.fillColor = [UIColor clearColor].CGColor;
layer.strokeColor = [UIColor redColor].CGColor;
layer.lineWidth = 3.0f;
layer.shouldRasterize = YES;//抗锯齿
[_viewController.view.layer addSublayer:layer];
//创建关键帧
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
//动画时间
animation.duration = 1;
animation.path = path.CGPath
;
//当动画完成,停留到结束位置
animation.removedOnCompletion = YES;
animation.fillMode = kCAFillModeForwards;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[_shopView.layer addAnimation:animation forKey:nil];
path = nil;
}
demo地址:贝塞尔曲线之加入购物车