iOS简单的方法实现购物车demo (动画,本地缓存)原创
金蝶云社区-honey缘木鱼
honey缘木鱼
6人赞赏了该文章 751次浏览 未经作者许可,禁止转载编辑于2019年06月06日 17:54:21

随着这次项目的迭代,很多设计界面的更改,对于前端而言,就代表一个项目重新开始,也就有机会重新整理了一下购物车的实现思路。

一.设计

  1. 界面


WechatIMG3.jpeg

2.要求

  • 点击购买有动画效果(类似饿了吗)

  • 点击购买后,弹出加减供用户选择

  • 点击底部购物车,用户快速浏览已选商品及商品的加减。

二.思路

  1. 动画实现-----贝塞尔曲线+组合动画实现。

  2. 有几处点击cell列表改变了数量,用通知模式(一对多)。

  3. 封装一个单独的购物车view,承载数量,价钱的变化。

  4. 创建一个本地缓存对象。

三.代码

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

  1. 下载地址

  2. 具体使用






本篇独发金蝶云社区

赞 6