iOS简单的方法实现购物车demo (动画,本地缓存)原创
6人赞赏了该文章
1,008次浏览
编辑于2019年06月06日 17:54:21
随着这次项目的迭代,很多设计界面的更改,对于前端而言,就代表一个项目重新开始,也就有机会重新整理了一下购物车的实现思路。
一.设计
界面
2.要求
点击购买有动画效果(类似饿了吗)
点击购买后,弹出加减供用户选择
点击底部购物车,用户快速浏览已选商品及商品的加减。
二.思路
动画实现-----贝塞尔曲线+组合动画实现。
有几处点击cell列表改变了数量,用通知模式(一对多)。
封装一个单独的购物车view,承载数量,价钱的变化。
创建一个本地缓存对象。
三.代码
1. 动画
(1).先计算出抛出点的开始及结束点,开始点为点击➕的point值,结束点为购物车的图片point,该点都是view相对于window的位置点。
//开始点 CGRect parentRect = [storeCell convertRect:storeCell.plusButton.frame toView:self.view]; [self JoinCartAnimationWithRect:parentRect]; //结束点 _endPointX = rect.origin.x + 15; _endPointY = rect.origin.y + 35;
(2).三点确定运动轨迹(抛物线)
UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:fromCenter]; [path addCurveToPoint:CGPointMake(_endPointX, _endPointY) controlPoint1:CGPointMake(startX, startY) controlPoint2:CGPointMake(startX - 180, startY - 200)]; CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; pathAnimation.path = path.CGPath;
(3).小红点也可以换成实物图片
_dotLayer = [CALayer layer]; _dotLayer.backgroundColor = [UIColor redColor].CGColor; _dotLayer.frame = CGRectMake(0, 0, 15, 15); _dotLayer.cornerRadius = (15 + 15) /4; [self.view.layer addSublayer:_dotLayer]; [self groupAnimation];
(4).组合动画
#pragma mark - 组合动画-(void)groupAnimation { CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; animation.path = _path.CGPath; animation.rotationMode = kCAAnimationRotateAuto; CABasicAnimation *alphaAnimation = [CABasicAnimation animationWithKeyPath:@"alpha"]; alphaAnimation.duration = 0.5f; 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"]; [_dotLayer addAnimation:groups forKey:nil]; [self performSelector:@selector(removeFromLayer:) withObject:_dotLayer afterDelay:0.5f]; }
(5).购物车的缩放动画
#pragma mark - CAAnimationDelegate- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { 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; [_shopCartView.imageView.layer addAnimation:shakeAnimation forKey:nil]; } }
2.用通知模式监听加减项目说量的变化
(1).在控制器内创建观察者及购物车view
//监听项目购买数量变化 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(addOrReduceProjectNum:) name:@"addOrReduceProjectNum" object:nil];
//购物车
-(void)setPayView{ CGFloat hight = KIsiPhoneX ? 83 : 49; _shopCartView = [[ShopCartView alloc]initWithFrame:CGRectMake(0, kScreenHeight-hight, kScreenWidth, 50) attribute:self storeID:44 storeName:@"全国总店"]; self.delegateShoppingCart = _shopCartView; CGRect rect = [self.view convertRect:_shopCartView. imageView.frame fromView:_shopCartView]; _endPointX = rect.origin.x + 15; _endPointY = rect.origin.y + 35; [self.view addSubview:_shopCartView]; }
(2).在cell列表中发送通知
NSDictionary *dict = @{@"cell":self,@"index":[NSNumber numberWithInteger:self.indexPath.row],@"num":[NSNumber numberWithInt:self.model.count],@"price":[NSNumber numberWithFloat:price],@"cellModel":self.model,@"isShowAnimation":isShowAnimation}; [[NSNotificationCenter defaultCenter] postNotificationName:@"addOrReduceProjectNum" object:dict];
(3).实现通知的方法
#pragma 监听项目数量变化-(void)addOrReduceProjectNum:(NSNotification*)notification { NSDictionary *dict = notification.object; int number = [dict[@"num"] intValue]; UITableViewCell *cell = dict[@"cell"]; NSString* isShowAnimation = dict[@"isShowAnimation"]; CommonModel *model=dict[@"cellModel"]; BOOL exist = TRUE; for (CommonModel *value in BUYLISTDATA.buyDataArray) { if(value.itemId == model.itemId) { exist = FALSE; if(number<=0) { [BUYLISTDATA removeObject:value]; }else{ value.count = number; } break; } } if(exist) { model.cell = (CommonCell *) cell; [BUYLISTDATA addObject:model]; } if (self.delegateShoppingCart&&[self.delegateShoppingCart respondsToSelector:@selector(addDeleteItem:)]) { [self.delegateShoppingCart addDeleteItem:[self calculationTotal]]; } CommonCell *storeCell = (CommonCell *) model.cell; [storeCell setItemNumber:number addToItem:FALSE]; if([isShowAnimation isEqualToString:@"YES"]) { CGRect parentRect = [storeCell convertRect:storeCell.plusButton.frame toView:self.view]; [self JoinCartAnimationWithRect:parentRect]; } }
关键点:
为保持购物车内数量增减和列表同步,我们需要给cell一个外部方法,在点击时做相应的更改。
-(void)setItemNumber:(int)number addToItem:(BOOL)isAddItem;
给加载购物车的控制器设置代理,购物车实现代理方法
@protocol addDeleteItemDelegate<NSObject>- (void)addDeleteItem:(CGFloat)totalPriceNumber;@end@interface ViewController : UIViewController@property(nonatomic,strong)CommonTableView*tableView;@property(nonatomic,weak)id<addDeleteItemDelegate>delegateShoppingCart;if (self.delegateShoppingCart&&[self.delegateShoppingCart respondsToSelector:@selector(addDeleteItem:)]) { [self.delegateShoppingCart addDeleteItem:[self calculationTotal]]; }
3. 购物车视图
实现代理的方法,购物车数量及价钱的变化
- (void)addDeleteItem:(CGFloat)totalPriceNumber { NSLog(@"%f",totalPriceNumber); if ((totalPrice<=0 && totalPriceNumber>0) || (totalPrice>0 && totalPriceNumber<=0)) { if (totalPriceNumber<=0) { redBadge.hidden = YES; enterBtn.backgroundColor = RGB(194, 194,194); }else{ redBadge.hidden = NO; enterBtn.backgroundColor = RGB(248, 94, 94); } } totalPrice =totalPriceNumber; NSString *textPrice = (totalPriceNumber-((int)totalPriceNumber)>0) ? [[NSString alloc]initWithFormat:@"¥%.1f",totalPriceNumber] : [[NSString alloc]initWithFormat:@"¥%d",(int)totalPriceNumber]; NSString *titlePrice =[NSString stringWithFormat:@"总价格: %@",textPrice]; NSMutableAttributedString *attributeStr = [[NSMutableAttributedString alloc] initWithString:titlePrice]; [attributeStr addAttribute:NSForegroundColorAttributeName value:RGB(248, 94, 94) range:NSMakeRange(4, titlePrice.length-4)]; totalPriceLbl.attributedText = attributeStr; num.text = [NSString stringWithFormat:@"%d",[self calculationTotalNum]]; commTableViewHeight = [BUYLISTDATA getCount] * cellHeight; if (commTableViewHeight>(kScreenHeight-hight)*2/3){ commTableViewHeight = (kScreenHeight-hight)*2/3; } self.tableView.frame = CGRectMake(0,50,kScreenWidth,commTableViewHeight); [self.tableView reloadData]; if([BUYLISTDATA getCount]<=0){ [self clearAllClick:NULL]; }else { // 在购物车移除cell [self removeOneCell]; } }
清空购物车内容
#pragma 清空数据 -(void) clearAllClick:(UIButton*)sender { if (sender != NULL){ for (CommonModel *model in BUYLISTDATA.buyDataArray) { CommonCell *viewCell = (CommonCell*)model.cell; [viewCell setItemNumber:0 addToItem:FALSE]; } } totalPrice = 0; toShow = FALSE; redBadge.hidden = YES; num.text = @""; enterBtn.backgroundColor = RGB(194, 194,194); totalPriceLbl.text = @"总价格:¥0"; [UIView animateWithDuration:0.2 animations:^{ showView.frame = CGRectMake(0, viewPostionY-hight, kScreenWidth,50); } completion:^(BOOL finished) { self.frame = CGRectMake(0,viewPostionY-hight,kScreenWidth,50); payView.frame = CGRectMake(0, self.frame.size.height-50, kScreenWidth, 50); showView.frame = CGRectMake(0, self.frame.size.height-50, kScreenWidth, 50); [BUYLISTDATA reset]; [self.tableView reloadData]; }]; }
4.本地缓存对象
创建单例对象,对购物车数据进行增删改查
@interface BuyListData : NSObject @property(nonatomic,strong)NSMutableArray *buyDataArray; - (instancetype)initWith; - (void)reset; - (void)removeObjectAtIndex:(NSUInteger)objectIndex; - (id)objectAtIndex:(NSUInteger)objectIndex; - (int)getCount; - (void)addObject:(id)object; - (void)removeObject:(id)object; + (BuyListData*)shareBuyListData; @end #define BUYLISTDATA [BuyListData shareBuyListData]
static BuyListData *data=nil; @implementation BuyListData+(BuyListData*)shareBuyListData { @synchronized(self){ if (data == nil) { data = [[BuyListData alloc] initWith]; } } return data; } -(instancetype)initWith { self = [super init]; if (self) { _buyDataArray = [[NSMutableArray alloc]init]; } return self; } -(void)reset { if (_buyDataArray.count>0) [_buyDataArray removeAllObjects]; } - (void)removeObjectAtIndex:(NSUInteger)objectIndex { if(_buyDataArray.count>objectIndex){ [_buyDataArray removeObjectAtIndex:objectIndex]; } } - (id)objectAtIndex:(NSUInteger)objectIndex { if(_buyDataArray.count>objectIndex){ return [_buyDataArray objectAtIndex:objectIndex]; } return nil; } - (int)getCount { return (int)_buyDataArray.count; } - (void)addObject:(id)object { [_buyDataArray addObject:object]; } - (void)removeObject:(id)object { [_buyDataArray removeObject:object]; }
四.demo
具体使用
本篇独发金蝶云社区
赞 6
6人点赞
还没有人点赞,快来当第一个点赞的人吧!
打赏
0人打赏
还没有人打赏,快来当第一个打赏的人吧!
推荐阅读