相对于上一篇博客(系统的批量删除),但是有可能在实际项目中我们需要自定义批量删除.
效果图如下:
思路如下:
1. 前面的思路和前两篇博客思路相同,这里不做详细介绍了
2. 相当于自定义cell.添加一个打钩控件
3. 给ZYWine模型设置一个 "记录打钩控件状态"的属性
3. 当用户每点击cell的时候,打钩控件是隐藏的,点击之后显示出来,并且可以删除
4. 点击cell的时候,控件出来会有动画,删除cell的时候,也有动画
代码如下:
ZYWine 文件
#import
/** 酒数据模型 */
@interface ZYWine : NSObject
/** 图片名 */
@property (nonatomic, copy) NSString *image;
/** 价格 */
@property (nonatomic, copy) NSString *money;
/** 酒名称 */
@property (nonatomic, copy) NSString *name;
/** 记录打钩控件的状态 */
@property(nonatomic,assign,getter=isChecked)BOOL clecked;
@end
@implementation ZYWine
@end
ZYWineCell文件
#import
@class ZYWine;
// 每一个cell
@interface ZYWineCell : UITableViewCell
/** 酒的数据模型 */
@property(nonatomic,strong)ZYWine * wine;
@end
#import "ZYWine.h"
@interface ZYWineCell ()
@property (nonatomic,weak) UIImageView *checkImageView;
@end
@implementation ZYWineCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
// 添加子控件
UIImageView *checkImageView = [[UIImageView alloc] init];
// 默认先把打钩控件隐藏
checkImageView.hidden = YES;
checkImageView.image = [UIImage imageNamed:@"check"];
[self.contentView addSubview:checkImageView];
self.checkImageView = checkImageView;
}
return self;
}
/** 给子控件设置位置 */
- (void)layoutSubviews
{
[super layoutSubviews];
// 设置打钩的位置和尺寸
CGFloat WH = 24;
CGFloat X = self.contentView.frame.size.width - WH - 10;
CGFloat Y = (self.contentView.frame.size.height - WH) * 0.5;
self.checkImageView.frame = CGRectMake(X, Y, WH, WH);
// 设置文字的宽度
CGRect frame = self.textLabel.frame;
frame.size.width = self.contentView.frame.size.width - WH - 20 - self.textLabel.frame.origin.x;
self.textLabel.frame = frame;
}
// 重写wine的set方法,把模型中的数据赋值进来
- (void)setWine:(ZYWine *)wine
{
_wine = wine;
self.imageView.image = [UIImage imageNamed:wine.image];
self.textLabel.text = wine.name;
self.detailTextLabel.text = [NSString stringWithFormat:@"¥%@",wine.money];
self.detailTextLabel.textColor = [UIColor orangeColor];
// 根据默认的checked属性确定打钩控件显示还是隐藏
if (wine.isChecked) { // 如果是打钩,设置打钩控件不隐藏
self.checkImageView.hidden = NO;
}else{ // 不是打钩,设置打钩控件隐藏
self.checkImageView.hidden = YES;
}
}
@end
ViewController 文件
#import
@interface ViewController : UIViewController
@end
#import "ViewController.h"
#import "MJExtension.h"
#import "ZYWineCell.h"
#import "ZYWine.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITableView *tableView;
/** 酒模型数组,装的都是酒模型 */
@property (strong,nonatomic) NSMutableArray *wineArray;
/** 记录用户选中行的索引 */
@property (nonatomic,strong) NSMutableArray *selectIndexPath;
@end
@implementation ViewController
// 初始化
- (NSMutableArray *)selectIndexPath
{
if (_selectIndexPath == nil) {
_selectIndexPath = [NSMutableArray array];
}
return _selectIndexPath;
}
// 懒加载
- (NSMutableArray *)wineArray
{
if (!_wineArray) {
_wineArray = [ZYWine mj_objectArrayWithFilename:@"wine.plist"];
}
return _wineArray;
}
- (void)viewDidLoad {
[super viewDidLoad];
}
#pragma -mark 按钮的点击方法
/** 删除按钮 */
- (IBAction)removeBtn {
// 获取要删除的酒模型
// NSMutableArray *deleteWine = [NSMutableArray array];
// for (ZYWine *wine in self.wineArray) {
// if (wine.isChecked) {
// [deleteWine addObject:wine];
// }
// }
// // 修改模型
// [self.wineArray removeObjectsInArray:deleteWine];
// // 刷新表格(会重新调用数据源的方法)
// [self.tableView reloadData];
NSMutableArray *deleteWine = [NSMutableArray array];
for (NSIndexPath *indexPath in self.selectIndexPath) {
// 把选中的cell模型添加到数组中
[deleteWine addObject:self.wineArray[indexPath.row]];
}
// 把选中的cell模型从wineArray中删除
[self.wineArray removeObjectsInArray:deleteWine];
// 局部刷新数据(设置动画)
[self.tableView deleteRowsAtIndexPaths:self.selectIndexPath withRowAnimation:UITableViewRowAnimationAutomatic];
// 清空数组
/*
这一步的原因: 因为当把选中的cell的索引保存在selectIndexPath数组中,然后把选中cell的索引对应的每一个模型都添加到deleteWine数组中,然后在wineArray数组中删除.
但是: 保存选中索引cell的数组selectIndexPath中扔保存着被删除cell的索引.但是wineArray数组中已经没有对应索引的模型了,所以会导致数组越界
*/
[self.selectIndexPath removeAllObjects];
}
#pragma -mark 实现数据源方法
/** 有多少行数据 */
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.wineArray.count;
}
/** 每一行数据的内容 */
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// NSLog(@"cellForRowAtIndexPath--%ld",indexPath.row);
// 定义一个重用标识
static NSString *ID = @"wine";
ZYWineCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
// 判断缓存池中是否有可重用的cell,如果没有就创建
if (cell == nil) {
cell = [[ZYWineCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
}
// 改变cell的前景色
// cell.tintColor = [UIColor redColor];
// 设置每一行数据
cell.wine = self.wineArray[indexPath.row];
return cell;
}
#pragma -mark 代理方法
/**
当选中这一行就会调用这个方法
*/
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ZYWine *wine = self.wineArray[indexPath.row];
// 一开始cleck的状态为NO,取反变为YES
// wine.clecked = !wine.clecked;
if (wine.isChecked) { // 之前是打钩的,现在取消打钩
wine.clecked = NO;
// 把之前打钩cell的索引,从数组中删除
[self.selectIndexPath removeObject:indexPath];
}else{ // 之前不是打钩的,现在打钩
// 把打钩的cell索引保存到数组中
wine.clecked = YES;
[self.selectIndexPath addObject:indexPath];
}
// 刷新表格(会重新调用数据源的方法)
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
@end