iOS - 购物车界面的实现

在商城类APP的开发中,购物车功能是必不可少的。
在上一个app的开发中生活又对我这个菜鸟下手了,我被安排实现购物车功能WTF ~.~ .吐槽归吐槽,功能还是要实现滴。。。

购物车

实现思路:

  1. 购物车界面实现的关键是对MVC模式开发的理解和运用。我们通过在Model中定义一个是否被选中的bool值(isSelect)来改变选择的状态。
    其实MVC这种运用场景还是很多的,比如我们要动态计算一个cell的高度的时候,我们通常也是会在model中去进行计算,然后将结果通过一个定义的常量暴露在.h文件中供其他调用。
  2. 自定义cell,这个就不多说了,不管是复杂的还是简单的cell大多数都是自定义的,这里复杂的数据可能用到富文本,比如这里现价和市场价我是一个label然后用富文本实现的。
  3. 多选的实现是在controller中声明了一个选中的数组,然后将选中的model保存到可变数组中。
  4. 代理的运用。这个功能使用到了很多代理的思想,底部结算区也是用代理实现的。(不建议用block,就是代理和block的优缺点比较吧)。

下面是代码的实现:

ShoppingCartModel.h

#import <Foundation/Foundation.h>

@interface ShoppingCartModel : NSObject
/**购物车ID*/
@property(nonatomic,strong)NSString *cartId ;

/**商品的编号*/
@property(nonatomic,strong)NSString *goodsNo ;

/**商品的id*/
@property(nonatomic,strong)NSString *goodsId ;

/**商品的图片*/
@property(nonatomic,strong)NSString *goodsImage ;

/**商品的名称*/
@property(nonatomic,strong)NSString *goodsName ;

/**商品的的市场价格*/
@property(nonatomic,strong)NSString *goodsMarketPrice ;

/**商品价格*/
@property(nonatomic,strong)NSString *goodsSystemPrice ;

/**商品的市场价格*/
@property(nonatomic,assign)NSInteger number ;

/**上次是否被选*/
@property (nonatomic, assign) BOOL isSelect;

-(instancetype)initWithDict:(NSDictionary *)dict ;
+(instancetype)ShoppingCartModelWithDict:(NSDictionary *)dict ;

@end

自定义cell声明代理方法
ShoppingCartTableViewCell.h

#import <UIKit/UIKit.h>
#import "ChoiceButton.h"

@class ShoppingCartTableViewCell,ShoppingCartModel,SureFormModel ;

@protocol ShoppingCartTableViewDelegate <NSObject>

@optional

/**选中*/
- (void)shopCartGoodViewCell:(ShoppingCartTableViewCell *)cell withSelectedModel:(ShoppingCartModel *)model;

/**添加、减少*/
- (void)shopCartGoodViewCellChange:(ShoppingCartTableViewCell *)cell ;

/**输入框事件*/
- (void)shopCartGoodViewCellTextField:(ShoppingCartTableViewCell *)cell;

@end

@interface ShoppingCartTableViewCell : UITableViewCell

/** 代理属性 */
@property (nonatomic ,weak)id<ShoppingCartTableViewDelegate>  delegate;

@property(nonatomic,strong) ShoppingCartModel *model ;

@end

这里完成cell的布局,就不贴代码了,主要是代理部分的代码
ShoppingCartTableViewCell.m

#pragma mark - 勾选按钮事件
-(void)choiceButtonAction:(UIButton *)button{
    
    ShoppingCartTableViewCell *cell = (ShoppingCartTableViewCell *)button.superview.superview;
    
    if ([self.delegate respondsToSelector:@selector(shopCartGoodViewCell:withSelectedModel:)]) {
        [self.delegate shopCartGoodViewCell:cell withSelectedModel:cell.model];
    }
}

#pragma mark - 商品数量的setter方法
- (void)setGoodsCount:(NSInteger)goodsCount{
    _goodsCount = goodsCount;
    _shopNumberTextField.text = [NSString stringWithFormat:@"%ld", (long)goodsCount] ;
}

#pragma mark - textFieldDelegete
-(void)textFieldDidEndEditing:(UITextField *)textField{
    ShoppingCartTableViewCell *cell = (ShoppingCartTableViewCell *)textField.superview.superview.superview;
    ShoppingCartModel *model = cell.model;
    
    if ([_shopNumberTextField.text integerValue] >= 99) {
        self.shopNumberTextField.text = [NSString stringWithFormat:@"%d", 99];
    }
    if ([_shopNumberTextField.text integerValue] <= 0) {
        self.shopNumberTextField.text = [NSString stringWithFormat:@"%d", 1];
    }
    
    model.number = [self.shopNumberTextField.text integerValue];
    //向服务器发送请求
    [self.delegate shopCartGoodViewCellTextField:self];
}


#pragma mark - 减按钮事件
-(void)minusButtonAction:(UIButton *)button{
    ShoppingCartTableViewCell *cell = (ShoppingCartTableViewCell *)button.superview.superview.superview;
    ShoppingCartModel *model = cell.model;
    if (_goodsCount != 1) {
        self.goodsCount = self.goodsCount - 1;
        model.number = self.goodsCount;
        //向服务器发送请求
        [self.delegate shopCartGoodViewCellChange:self];
    }
    
}

#pragma mark - 加按钮事件
-(void)plusButtonAction:(UIButton *)button{
    ShoppingCartTableViewCell *cell = (ShoppingCartTableViewCell *)button.superview.superview.superview;
    ShoppingCartModel *model = cell.model;
    
    //换成最大库存
    if (_goodsCount <= 99) {
        self.goodsCount = self.goodsCount + 1;
        model.number = self.goodsCount;
    }else{
        self.goodsCount = 99;
        model.number = self.goodsCount;
    }
    //向服务器发送请求
    [self.delegate shopCartGoodViewCellChange:self];
    
}

底部结算区:
ShoppingCartBottomMenuView.h

#import <UIKit/UIKit.h>
#import "ChoiceButton.h"

NS_ASSUME_NONNULL_BEGIN

@class ShoppingCartBottomMenuView ;

@protocol ShoppingCartBottomMenuViewDelegate <NSObject>

-(void)shoppingCartbottomPriceView:(ShoppingCartBottomMenuView *)bottonView;
/**
 付款
 */
-(void)shoppingCartPayAccountsButton:(ShoppingCartBottomMenuView *)bottonView;
/**
 删除
 */
-(void)shoppingCartDeleteButton:(ShoppingCartBottomMenuView *)bottonView;

@end

@interface ShoppingCartBottomMenuView : UIView

@property(nonatomic,strong)ChoiceButton *choiceButton ; //全选

@property(nonatomic,strong)UILabel *choiceLabel ; //选择状态

@property(nonatomic,strong)UILabel *totalPriceLabel ; //总价

@property(nonatomic,strong)UIButton *payAccountsButton ; //付款按钮

@property(nonatomic,strong)UIButton *deleteButton ; //删除按钮

/**结算字符串*/
@property (nonatomic, copy) NSString *payStr;
/**合计字符串*/
@property (nonatomic, strong) NSString *attAllStr;
@property (nonatomic, strong) NSString *changeStr;
@property (nonatomic, assign) BOOL isSelectBtn ;

@property (weak, nonatomic) id<ShoppingCartBottomMenuViewDelegate> delegate;

@end

ShoppingCartBottomMenuView.m

- (void)setIsSelectBtn:(BOOL)isSelectBtn{
    _choiceButton.selected = isSelectBtn;
    if ([self.delegate respondsToSelector:@selector(shoppingCartbottomPriceView:)]) {
        [self.delegate shoppingCartbottomPriceView:self];
    }
}

- (void)choiceButtonAction:(UIButton *)button{
    button.selected = !button.isSelected;
    
    if (button.selected) {
        self.choiceLabel.text = @"全不选" ;
    }else{
        self.choiceLabel.text = @"全选" ;
    }

    if ([self.delegate respondsToSelector:@selector(shoppingCartbottomPriceView:)]) {
        [self.delegate shoppingCartbottomPriceView:self];
    }
}

-(void)payAccountsButtonAction{
    if ([self.delegate respondsToSelector:@selector(shoppingCartPayAccountsButton:)]) {
        [self.delegate shoppingCartPayAccountsButton:self];
    }
}

-(void)deleteButtonAction{
    if ([self.delegate respondsToSelector:@selector(shoppingCartDeleteButton:)]) {
        [self.delegate shoppingCartDeleteButton:self];
    }
}

- (void)setPayStr:(NSString *)payStr{
    _payStr = payStr ;
    
    if ([payStr isEqualToString:@""]) {
        [self.payAccountsButton setTitle:@"结算" forState:UIControlStateNormal];
    }else{
        [self.payAccountsButton setTitle:[NSString stringWithFormat:@"结算%@", payStr] forState:UIControlStateNormal];
    }
    
    
}

- (void)setAttAllStr:(NSString *)attAllStr{
    _attAllStr = [NSString stringWithFormat:@"合计:¥%@", attAllStr];
    NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc]initWithString:_attAllStr];
    
    //添加属性
    NSRange range = { 4,_attAllStr.length - 4};
    
    NSRange range1 = {3, _attAllStr.length - 3};
    
    [attStr addAttribute:NSFontAttributeName value:FONT(22 * kFitWithWidth) range:NSMakeRange(3, 1)] ;
    
    [attStr addAttribute:NSFontAttributeName value:FONT_BOLD(32 * kFitWithWidth) range:range];
    [attStr addAttribute:NSForegroundColorAttributeName value:RGB(247, 89, 64) range:range1];
    self.totalPriceLabel.attributedText = attStr;
}

在controller中
ShoppingCartViewController.m

/**选中的商品模型数组*/
@property(nonatomic,strong)NSMutableArray *selectedArray ;

/**底部结算区*/
@property(nonatomic,strong)ShoppingCartBottomMenuView *menuView ;

/**总价格*/
@property (nonatomic, assign) double allSum ;

#pragma mark - ShoppingCartTableViewDelegate
/**添加、减去*/
- (void)shopCartGoodViewCellChange:(ShoppingCartTableViewCell *)cell{
    _allSum = 0;
    for (ShoppingCartModel *model in self.selectedArray) {
        self.allSum += [model.goodsSystemPrice floatValue] * model.number ;
        
    }
    _menuView.attAllStr = [NSString stringWithFormat:@"%.2f", self.allSum];

    [self insertOrUpdateShoppingCar:cell] ;

}

- (void)shopCartGoodViewCellTextField:(ShoppingCartTableViewCell *)cell{
    _allSum = 0;
    for (ShoppingCartModel *model in self.selectedArray) {
        self.allSum += [model.goodsSystemPrice floatValue] * model.number ;
    }
    _menuView.attAllStr = [NSString stringWithFormat:@"%.2f", self.allSum];
    
    [self insertOrUpdateShoppingCar:cell] ;
}

/**选中*/
- (void)shopCartGoodViewCell:(ShoppingCartTableViewCell *)cell withSelectedModel:(ShoppingCartModel *)model{
    
    if ([self.selectedArray containsObject:model]) {
        [self.selectedArray removeObject:model];
        //每当取消选中商品
        self.menuView.choiceButton.selected = NO;
        model.isSelect = NO;
        
        self.allSum -= [model.goodsSystemPrice floatValue] * model.number;
    }else{
        //选中之后
        [self.selectedArray addObject:model];
        model.isSelect = YES;
        
        self.allSum += [model.goodsSystemPrice floatValue] * model.number;
    }
    
    if (self.selectedArray.count == self.shoppingCartListArray.count) {
        //全部店铺添加
        self.menuView.choiceButton.selected = YES;
        self.menuView.choiceLabel.text = @"全不选" ;
    }else{
        self.menuView.choiceButton.selected = NO;
        self.menuView.choiceLabel.text = @"全选" ;
    }
    
    self.menuView.attAllStr = [NSString stringWithFormat:@"%.2f", self.allSum];
    
    if (self.selectedArray.count > 0) {
        self.menuView.payStr = [NSString stringWithFormat:@"(%lu)", self.selectedArray.count];
    }else{
        self.menuView.payStr = @"" ;
    }
    
    [self.shoppingCartTableView reloadData];

}

#pragma mark - ShoppingCartBottomMenuViewDelegate
//底部选中
-(void)shoppingCartbottomPriceView:(ShoppingCartBottomMenuView *)bottonView{
    if (bottonView.choiceButton.selected) {
        [self.selectedArray removeAllObjects];
        
        [self.selectedArray addObjectsFromArray:self.shoppingCartListArray];
        for (ShoppingCartModel *model in self.shoppingCartListArray) {
            model.isSelect = YES;
            
        }
        self.allSum = 0.0;
        //计算总价格
        for (ShoppingCartModel *model in self.selectedArray) {
            self.allSum += [model.goodsSystemPrice floatValue] * model.number;
        }
    }else{
        [self.selectedArray removeAllObjects];
        
        for (ShoppingCartModel *model in self.shoppingCartListArray) {
            model.isSelect = NO;
        }
        self.allSum = 0.0;
    }
    bottonView.attAllStr = [NSString stringWithFormat:@"%.2f", self.allSum];
    if (self.selectedArray.count > 0) {
        self.menuView.payStr = [NSString stringWithFormat:@"(%lu)", self.selectedArray.count];
    }else{
        self.menuView.payStr = @"" ;
    }
    [self.shoppingCartTableView reloadData];
    
}

大致思路就是这样。我们就可以实现购物车功能了。
有不足的地方希望大家积极补充。共勉。。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,928评论 6 509
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,748评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,282评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,065评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,101评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,855评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,521评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,414评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,931评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,053评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,191评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,873评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,529评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,074评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,188评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,491评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,173评论 2 357

推荐阅读更多精彩内容