iOS 一一 自定义cell按钮的点击事件(代理)

效果图如下:



效果分析:

1. 先布局界面,界面由UITableView,和底部的UIView构成,所以控制器只需要继承自UIViewController就可以了

2. 设置UITableView的界面,给每个cell中设置数据模型. 给底部UIView添加控件及设置约束

3. UITableView每一个cell上面都有减号,加号按钮,应该自定义按钮

4. 当点击加号,减号按钮时,将改变UIView上面的总价. 


代理的使用步骤:

  • 定义一份代理协议

    • 协议名字的格式一般是:类名 + Delegate
      • 比如UITableViewDelegate
    • 设计代理的细节
      • 一般都是@optional(让代理可以有选择性去实现一些代理方法)
      • 方法名一般都以类名开头
        • 比如- (void)scrollViewDidScroll:
      • 一般都需要将对象本身传出去
        • 比如tableView的代理方法都会把tableView本身传出去
    • 必须要遵守NSObject协议(基协议)
      • 比如@protocol XMGWineCellDelegate <NSObject>
  • 声明一个代理属性

    • 代理的类型格式:id<协议> delegate
@property (nonatomic, weak) id<XMGWineCellDelegate> delegate;
  • 设置代理对象

  • 代理对象遵守协议,实现协议里面相应的方法

  • 当控件内部发生了一些事情,就可以调用代理的代理方法通知代理

    • 如果代理方法是@optional,那么需要判断方法是否有实现,直接调用可能会报错
if ([self.delegate respondsToSelector:@selector(wineCellDidClickPlusButton:)]) {
    [self.delegate wineCellDidClickPlusButton:self];
}
具体代码如下:

自定义按钮ZYOperationButton文件

#import <UIKit/UIKit.h>

// 自定义按钮

@interface ZYOperationButton : UIButton

@end

@implementation ZYOperationButton

// 当从storyboard中或xib中加载完后会调用这个方法.\
    awakeFromNib是在viewDidLoad之前发生的。就是如果想要对view本身进行一些例如背景颜色,透明度之类的设置就只能在awakeFromNib里面进行,因为view被load之后再改就来不及了,所以只能在view被load之前进行设置,就是awakeFromNib。

- (void)awakeFromNib
{
    [super awakeFromNib];
    // 设置边框的宽度
    self.layer.borderWidth = 1.0f;
    // 设置边框颜色
    self.layer.borderColor = [UIColor orangeColor].CGColor;
    // 设置圆角半径
    self.layer.cornerRadius = self.frame.size.width * 0.5;
    
}

@end

ZYWine文件

#import <Foundation/Foundation.h>

@interface ZYWine : NSObject

/** 图片名 */
@property (nonatomic, copy) NSString *image;

/** 酒的名字 */
@property (nonatomic, copy) NSString *name;

/** 价格 */
@property (nonatomic, copy) NSString *money;

/** 购买数 */
@property(nonatomic,assign) int count;

@end

@implementation ZYWine

@end

Main.storyboard 文件




ZYWineCell文件

#import <UIKit/UIKit.h>
@class ZYWine , ZYWineCell;

@protocol ZYWineCellDelegate <NSObject>

@optional
// 协议中的方法
// 哪个cell的按钮被点击了.传一个cell
- (void)wineCellDidClickAddButton :(ZYWineCell *)cell;
- (void)wineCellDidClickMinusButton :(ZYWineCell *)cell;

@end

@interface ZYWineCell : UITableViewCell

/** 酒模型 */
@property(nonatomic,strong)ZYWine * wine;

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

@end

#import "ZYWine.h"
@interface ZYWineCell ()
@property (weak, nonatomic) IBOutlet UIImageView *icon;
@property (weak, nonatomic) IBOutlet UILabel *title_Label;
@property (weak, nonatomic) IBOutlet UILabel *price_Label;
/** 购买数 */
@property (weak, nonatomic) IBOutlet UILabel *buyCount;

@property (weak, nonatomic) IBOutlet UIButton *minusBtn;

@end

@implementation ZYWineCell

- (void)awakeFromNib
{
    [super awakeFromNib];
    // 当加载完storyboard的时候,把减号按钮设为不可点击
    self.minusBtn.enabled = NO;
    
}

- (void)setWine:(ZYWine *)wine
{
    // 通过酒数据模型设置数据
    _wine = wine;
    self.icon.image = [UIImage imageNamed:wine.image];
    self.title_Label.text = wine.name;
    self.price_Label.text = [NSString stringWithFormat:@"¥%@",wine.money];
    
    // 根据count决定buyCount显示的文字
    self.buyCount.text = [NSString stringWithFormat:@"%d",wine.count];
    
    // 根据count决定减号按钮是否能点击
    self.minusBtn.enabled = (wine.count > 0);
}

#pragma -mark 按钮点击事件
// 这样做的好处: 降低了耦合度,cell和控制器的关联不太大,如果在其他地方要使用到cell,监听cell的通知就可以了
- (IBAction)addBtnClick {
    
    //1. 当点击添加按钮,buyCount增加
    self.wine.count ++;
    
    //2. 修改界面(通过新的模型来修改界面)\
    因为在cell里面不能使用self.tableView reloadData 刷新数据\
    刷新数据的本质就是重新调用数据源方法,通过新的模型设置新的数据,既然如此,我们可以直接在内部通过\
    使用新的模型来设置数据
    self.buyCount.text = [NSString stringWithFormat:@"%d",self.wine.count];
    
    //3. 当点击添加按钮的时候,使减号按钮可以点击
    self.minusBtn.enabled = YES;
    
    //4. 当点击加号按钮的时候,通知代理(调用代理的方法)
    //判断这个方法是否实现,如果实现就调用代理方法
    if ([self.delegate respondsToSelector:@selector(wineCellDidClickAddButton:)]) {
        [self.delegate wineCellDidClickAddButton:self];
    }
    
}

- (IBAction)minusBtnClick {
    
    
    self.wine.count --;
    
    self.buyCount.text = [NSString stringWithFormat:@"%d",self.wine.count];
    
    // 当buyCount为0,的时候,设置删除按钮为不可点
    if (self.wine.count == 0) {
        self.minusBtn.enabled = NO;
    }
    
    // 当点击减号按钮的时候,通知代理
    if ([self.delegate respondsToSelector:@selector(wineCellDidClickMinusButton:)]) {
        [self.delegate wineCellDidClickMinusButton:self];
    }
}

@end

ViewController文件

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@end

#import "ZYWineCell.h"
#import "MJExtension.h"
#import "ZYWine.h"

@interface ViewController () <UITableViewDataSource,ZYWineCellDelegate>

@property (weak, nonatomic) IBOutlet UITableView *tableView;

/** 装所有的酒模型的数组 */
@property (nonatomic,strong) NSArray *wineArray;

@property (weak, nonatomic) IBOutlet UILabel *totalPrice;

@property (weak, nonatomic) IBOutlet UIButton *buyButton;

@property (weak, nonatomic) IBOutlet UIButton *clearButton;

/** 购物车对象 */
@property (nonatomic, strong) NSMutableArray *shoppingCart;

@end

@implementation ViewController

// 初始化
- (NSMutableArray *)shoppingCart
{
    if (_shoppingCart == nil) {
        _shoppingCart = [NSMutableArray array];
    }
    return _shoppingCart;
}

// 懒加载
- (NSArray *)wineArray
{
    if (_wineArray == nil) {
        _wineArray = [ZYWine mj_objectArrayWithFilename:@"wine.plist"];
        
    }
    return _wineArray;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    
    // 设置一开始没有购买的时候.清除购物车,购买按钮为不可点击
    self.clearButton.enabled = NO;
    self.buyButton.enabled = NO;
    
}

#pragma -mark ZYWineCellDelegate
- (void)wineCellDidClickAddButton:(ZYWineCell *)cell
{
    // 计算总价
    int totalMoney = self.totalPrice.text.intValue + cell.wine.money.intValue;
    self.totalPrice.text = [NSString stringWithFormat:@"%d",totalMoney];
    // 当点击加号按钮的时候,把buyButton,clearButton可点击
    self.buyButton.enabled = YES;
    self.clearButton.enabled = YES;
    
    // 把购买的wine都放到购物车中
    // 判断当前shoppingCart中有没有这个选中的wine
    if (![self.shoppingCart containsObject:cell.wine]) {
        
        [self.shoppingCart addObject:cell.wine];
    }

}

- (void)wineCellDidClickMinusButton:(ZYWineCell *)cell
{
    // 计算总价
    int totalMoney = self.totalPrice.text.intValue - cell.wine.money.intValue;
    self.totalPrice.text = [NSString stringWithFormat:@"%d",totalMoney];
    
    self.buyButton.enabled = totalMoney > 0;
    self.clearButton.enabled = totalMoney > 0;

    // 当用户把购买的某一个wine的数量减为0的时候,\
        把cell.wine从shoppingCart中移除
    if (cell.wine.count == 0) {
        [self.shoppingCart removeObject:cell.wine];
    }
    
}

#pragma -mark 按钮的点击事件
- (IBAction)clearBtn {
    // 注意: 当使用KVO的时候,不管在任何地方修改count的值,都会调用 observeValueForKeyPath:这个方法,然后修改totalPrice的值.
    
    //2. 遍历所有的模型,把模型的count设为0
    for (ZYWine *wine in self.shoppingCart) {
        wine.count = 0;
    }
    
    //1. 把totalPrice设为0
    self.totalPrice.text = @"0";
    
    //3. 刷新表格
    [self.tableView reloadData];
    
    //4. 当点击清空购物车按钮后,设置buyButton,clearButton设为不可点击
    self.buyButton.enabled = NO;
    self.clearButton.enabled = NO;
    
    //5. 当用户清除购物车的时候,把shoppingCart数组中的wine全部清空
    [self.shoppingCart removeAllObjects];
    
}

- (IBAction)buyBtn {
    
    // 当点击购买按钮的时候.打印购买酒的信息
    for (ZYWine *wine in self.shoppingCart) {
            NSLog(@"您购买了%d瓶%@",wine.count,wine.name);
    }
    
}
#pragma -mark  UITableViewDataSource

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return self.wineArray.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *ID = @"wine";
    ZYWineCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
    // 设置数据
    cell.wine = self.wineArray[indexPath.row];
    
    // 设置cell的代理为当前控制器
    cell.delegate = self;
    
    return cell;
}

@end

注意: 有多种方式实现 自定义cell按钮的点击事件,比如使用通知机制,KVO都可以实现.请关注后续的博客,将使用这两种方式来解决自定义cell中控件的点击事件


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

white camel

感谢支持~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值