- 1.1 下载地址
- 2.1 商品的cell
- 2.2 开(下)单界面
- 2.3 下单商品的控制器VC
- 2.4 动画处理工具类 JoinCartAnimationTool
引言
将商品图片icon 移动到购物车iocn的位置的动画效果:
应用场景:购物车模块,将商品添加商品到购物车
I、demo下载
1.1 下载地址
从CSDN下载Demo:https://download.csdn.net/download/u011018979/20045082
1、应用场景:购物车模块,将商品添加商品到购物车
2、文章地址:https://blog.csdn.net/z929118967/article/details/103660899
II 、代码实现
添加商品到购物车的事件传递,由cell->V->VC 核心处理代码在工具类JoinCartAnimationTool中
BillingRightCell.m
- 添加商品按钮的动画处理
[self.counterV.animationSubject subscribeNext:^(UIButton *btn) { @strongify(self); if (btn) { if ([self.delegate respondsToSelector:@selector(performAnimationWithCell:buttonView:)]) { [self.delegate performAnimationWithCell:self buttonView:self.iconImgV]; } } }];
2.2 开(下)单界面
BillingView
- 处理动画事件
#pragma mark - BillingRightCellDelegate - (void)performAnimationWithCell:(BillingRightCell *)cell buttonView:(UIImageView *)view { // CGRect parentRect = [cell convertRect:view.frame toView:self]; if (self.joinCartAnimationWithViewblock) { self.joinCartAnimationWithViewblock(view); } }
2.3 下单商品的控制器VC
展示商品数据的VC:BillingViewController
- 处理动画
[_vcView setJoinCartAnimationWithViewblock:^(id _Nonnull sender) { //sender 即添加按钮的控件 //btn.imageView:展示购物车icon的imageView //weakSelf.view:当前控制器的视图 [[weakSelf AnimationTool] joinCartAnimationWithView:sender toView:weakSelf.topButtonView.shoppingBtn.btn.imageView inView:weakSelf.view]; }];
- 处理动画的工具类属性
@property (strong, nonatomic) JoinCartAnimationTool *AnimationTool; - (JoinCartAnimationTool *)AnimationTool{ if (nil == _AnimationTool) { QCTJoinCartAnimationTool *tmpView = [[JoinCartAnimationTool alloc]init]; _AnimationTool = tmpView; } return _AnimationTool; }
2.4 动画处理工具类 JoinCartAnimationTool
.h
/** @param imageView 移动的View: 例如商品图片 @param boxImgV view移动的最后目标视图: 例如购物车icon控件 @param inView imageView boxImgV 参考的坐标系。例如购物车VC的View */ -(void)joinCartAnimationWithView:(UIImageView *)imageView toView:(UIView*)boxImgV inView:(UIView*)inView;
.m
#import "JoinCartAnimationTool.h" @interface JoinCartAnimationTool () /** 用于动画 */ @property (strong, nonatomic) UIBezierPath *path; @property (assign, nonatomic) CGFloat animationDuration; @property (strong, nonatomic) CALayer *dotLayer; //self.topButtonView.shoppingBtn.btn.imageView @property (strong, nonatomic) UIView *endView; @end @implementation JoinCartAnimationTool - (instancetype)init { self = [super init]; if (self) { self.animationDuration = 0.5f; } return self; } #pragma mark - ******** joinCartAnimationWithRect /** 以inView为参考,计算开始位置和结束位置的rect @param imageView 移动的View: 例如商品图片 @param boxImgV view移动的最后目标视图: 例如购物车icon控件 @param inView imageView boxImgV 参考的坐标系。例如购物车VC的View */ -(void)joinCartAnimationWithView:(UIImageView *)imageView toView:(UIView*)boxImgV inView:(UIView*)inView { self.endView = boxImgV; CGRect rect = [imageView.superview convertRect:imageView.frame toView:inView]; CGRect endRect = [boxImgV.superview convertRect:boxImgV.frame toView:inView]; CGPoint endPoint = CGPointMake(endRect.origin.x + endRect.size.width/2, endRect.origin.y + endRect.size.height/2); CGFloat startX = rect.origin.x+rect.size.width/2; CGFloat startY = rect.origin.y+rect.size.height/2; _path= [UIBezierPath bezierPath]; [_path moveToPoint:CGPointMake(startX, startY)]; [_path addLineToPoint:CGPointMake(endPoint.x, endPoint.y)]; // [_path addCurveToPoint:CGPointMake(endPoint.x, endPoint.y) // controlPoint1:CGPointMake(startX, startY) // controlPoint2:CGPointMake(startX - 180, startY - 200)]; _dotLayer = [CALayer layer]; // _dotLayer.backgroundColor = [UIColor purpleColor].CGColor; NSData * tempArchive = [NSKeyedArchiver archivedDataWithRootObject:imageView]; UIImageView *copyImgV = [NSKeyedUnarchiver unarchiveObjectWithData:tempArchive]; UIImage *image = [self circleImage:copyImgV]; _dotLayer.contents = (__bridge id)image.CGImage; _dotLayer.frame = imageView.frame; [inView.layer addSublayer:_dotLayer]; [self groupAnimation]; } -(UIImage *)circleImage:(UIImageView *)imageView{ UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 0); [[UIBezierPath bezierPathWithOvalInRect:imageView.bounds] addClip]; [imageView drawRect:imageView.bounds]; imageView.image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return imageView.image; } -(void)groupAnimation { CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; animation.path = _path.CGPath; animation.rotationMode = kCAAnimationLinear; CABasicAnimation *alphaAnimation1 = [CABasicAnimation animationWithKeyPath:@"bounds"]; alphaAnimation1.duration = 0.1; alphaAnimation1.repeatCount = 1; alphaAnimation1.fromValue = [NSValue valueWithCGRect:CGRectMake(0, 0, _dotLayer.bounds.size.width*1.5, _dotLayer.bounds.size.height*1.5)]; alphaAnimation1.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, _dotLayer.bounds.size.width, _dotLayer.bounds.size.height)]; alphaAnimation1.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; [_dotLayer addAnimation:alphaAnimation1 forKey:@"bounds"]; CABasicAnimation *alphaAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; alphaAnimation.duration = self.animationDuration; 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 = self.animationDuration; groups.removedOnCompletion = NO; groups.fillMode = kCAFillModeForwards; groups.delegate = self; // [groups setValue:@"groupsAnimation" forKey:@"animationName"]; [_dotLayer addAnimation:alphaAnimation forKey:@"cornerRadius"]; [_dotLayer addAnimation:groups forKey:nil]; [self performSelector:@selector(removeFromLayer:) withObject:_dotLayer afterDelay:self.animationDuration]; // WS(weakSelf); // dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.animationDuration/2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // [weakSelf playingBoxAnimation]; // }); } - (void)removeFromLayer:(CALayer *)layerAnimation{ [layerAnimation removeFromSuperlayer]; } #pragma mark - CAAnimationDelegate - (void)animationDidStart:(CAAnimation *)anim{ } - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { // 完成可以使用比例动画scale UIView *endView = self.endView; CABasicAnimation *alphaAnimation1 = [CABasicAnimation animationWithKeyPath:@"bounds"]; alphaAnimation1.duration = 0.1; alphaAnimation1.repeatCount = 1; alphaAnimation1.fromValue = [NSValue valueWithCGRect:CGRectMake(0, 0, endView.bounds.size.width*1.5, endView.bounds.size.height*1.5)]; alphaAnimation1.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, endView.bounds.size.width, endView.bounds.size.height)]; alphaAnimation1.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; [endView.layer addAnimation:alphaAnimation1 forKey:@"bounds"]; } @end
see also
- (定点缩放弹窗)的应用场景:iOS 常用动画之【 定点缩放弹窗】利用锚点anchorPoint进行实现(包含完整demo源码)
1、会员详情的右侧下拉操作菜单
2、浏览器的右侧下拉菜单
3、原文:https://kunnan.blog.csdn.net/article/details/84618986
4、demo下载地址:https://download.csdn.net/download/u011018979/16092830
5、相关文章:利用锚点anchorPoint进行实现
iOS Document Scanner:矩形边缘识别(边缘检测 ) CIDetectorTypeRectangle