// // MTGridSelectView.m // MTGridSelectDemo // // Created by mambaxie on 2019/1/19. // Copyright © 2019年 tencent. All rights reserved. // #import "MTGridSelectView.h" #import "MTGridSelectConfig.h" #define kItemContentViewCellReuseIdentifier @"kItemContentViewCellReuseIdentifier" @interface MTGridSelectModel : NSObject @property (nonatomic, strong) id model; @property (nonatomic, assign) MTGridItemState state; @property (nonatomic, strong) UIView *itemView; @end @implementation MTGridSelectModel @end @interface MTGridSelectView () @property (nonatomic, strong) MTGridSelectConfig *config; @property (nonatomic, copy) void (^setupConfigBlock)(MTGridSelectConfig * _Nonnull); @property (nonatomic, copy) MTGridDidSetupItemContentViewBlock didSetupItemContentViewBlock; @property (nonatomic, copy) MTGridItemStateChangedBlock itemStateChangedBlock; @property (nonatomic, copy) void (^selectValueChangedBlock)(NSArray *selectedModels); @property (nonatomic, copy) NSArray *itemModels; @property (nonatomic, strong) MTGridSelectModel *previousSelectItemModel; @property (nonatomic, strong) NSMutableIndexSet *seletedIndexSet; @end @implementation MTGridSelectView - (instancetype)init { if (self = [super init]) { [self setupConfig]; } return self; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { [self setupConfig]; } return self; } - (void)setupConfig { MTGridSelectConfig *config = [[MTGridSelectConfig alloc] init]; config.contentWidth = [UIScreen mainScreen].bounds.size.width; config.contentInset = UIEdgeInsetsMake(15, 15, 15, 15); config.rowSpacing = 10.0; config.columnSpacing = 10.0; config.maxColumn = 3; config.itemRatio = 0.3; config.itemHeight = 0.0; config.itemSize = CGSizeZero; config.multiple = NO; config.maxSelecteCount = 3; self.config = config; } + (instancetype)gridSelectViewWithItemModels:(NSArray *)itemModels setupConfig:(void(^)(MTGridSelectConfig *config))setupConfigBlock didSetupItemContentView:(MTGridDidSetupItemContentViewBlock)didSetupItemContentViewBlock itemStateChanged:(MTGridItemStateChangedBlock)itemStateChangedBlock selectValueChanged:(void(^)(NSArray *selectedModels))selectValueChangedBlock { MTGridSelectView *grideSeletView = [[self alloc] init]; grideSeletView.seletedIndexSet = [[NSMutableIndexSet alloc] init]; grideSeletView.originalModels = itemModels; NSMutableArray *itemModelsM = [NSMutableArray array]; for (id model in itemModels) { MTGridSelectModel *itemModel = [[MTGridSelectModel alloc] init]; itemModel.state = MTGridItemStateNormal; itemModel.model = model; [itemModelsM addObject:itemModel]; } grideSeletView.itemModels = [itemModelsM copy]; grideSeletView.setupConfigBlock = setupConfigBlock; grideSeletView.didSetupItemContentViewBlock = didSetupItemContentViewBlock; grideSeletView.itemStateChangedBlock = itemStateChangedBlock; grideSeletView.selectValueChangedBlock = selectValueChangedBlock; grideSeletView.clipsToBounds = NO; [grideSeletView createAndLayoutItemContentViews]; return grideSeletView; } - (void)setFrame:(CGRect)frame { [super setFrame:frame]; _collectionView.frame = self.bounds; } - (NSArray *)selectedItems { return [self.originalModels objectsAtIndexes:self.seletedIndexSet]; } - (NSInteger)itemTotalCount { return self.originalModels.count; } - (void)reloadDataWithItemModels:(NSArray *)itemModels { NSMutableArray *itemModelsM = [NSMutableArray array]; for (id model in itemModels) { MTGridSelectModel *itemModel = [[MTGridSelectModel alloc] init]; itemModel.state = MTGridItemStateNormal; itemModel.model = model; [itemModelsM addObject:itemModel]; } self.originalModels = itemModels; self.itemModels = [itemModelsM copy]; [self.collectionView reloadData]; } /// collectionViewCell 点击改变状态 - (void)changeItemViewStateAtIndex:(NSInteger)index { MTGridSelectModel *itemModel = self.itemModels[index]; MTGridItemState newState = MTGridItemStateNormal; if (self.config.multiple) { // 多选 if (itemModel.state == MTGridItemStateNormal) { // 超过上限 if (self.selectedItems.count >= self.config.maxSelecteCount) { if (self.limitBlock) { self.limitBlock(); } return; } newState = MTGridItemStateSelected; } else if (itemModel.state == MTGridItemStateSelected) { newState = MTGridItemStateNormal; } } else { // 单选 self.previousSelectItemModel.state = MTGridItemStateNormal; NSInteger previousIndex = [self.itemModels indexOfObject:self.previousSelectItemModel]; [self.seletedIndexSet removeIndex:previousIndex]; if (self.previousSelectItemModel) { self.itemStateChangedBlock(self.previousSelectItemModel.itemView, self.previousSelectItemModel.model, self.previousSelectItemModel.state, YES); } newState = MTGridItemStateSelected; self.previousSelectItemModel = itemModel; } [self changeItemStateAtIndexs:@[@(index)] state:newState changeByInner:YES]; } /// 选中指定下标 - (void)selectItemAtIndex:(NSInteger)index { [self selectItemAtIndexs:@[@(index)]]; } /// 选中多个指定下标 - (void)selectItemAtIndexs:(NSArray *)indexs { [self changeItemStateAtIndexs:indexs state:MTGridItemStateSelected changeByInner:NO]; } /// 全选 - (void)selectAllItem { [self changeAllItemViewState:MTGridItemStateSelected]; } /// 全不选 - (void)deselectAllItem { [self changeAllItemViewState:MTGridItemStateNormal]; } /// 改变指定下标状态 - (void)changeItemStateAtIndex:(NSInteger)index state:(MTGridItemState)state { [self changeItemStateAtIndexs:@[@(index)] state:state changeByInner:NO]; } /// 改变多个下标状态 - (void)changeItemStateAtIndexs:(NSArray *)indexs state:(MTGridItemState)state changeByInner:(BOOL)changeByInner { BOOL isChanged = NO; for (NSNumber *indexNumber in indexs) { MTGridSelectModel *itemModel = self.itemModels[[indexNumber integerValue]]; if (itemModel.state != state) { itemModel.state = state; if (MTGridItemStateSelected == state) { [self.seletedIndexSet addIndex:indexNumber.integerValue]; } else { [self.seletedIndexSet removeIndex:indexNumber.integerValue]; } if (self.itemStateChangedBlock) { self.itemStateChangedBlock(itemModel.itemView, itemModel.model, itemModel.state, changeByInner); } isChanged = YES; } if (!self.config.multiple) { // 单选 self.previousSelectItemModel = itemModel; } } if (self.selectValueChangedBlock && isChanged) { self.selectValueChangedBlock([self.originalModels objectsAtIndexes:self.seletedIndexSet]); } } - (void)changeAllItemViewState:(MTGridItemState)state { NSMutableArray * array = [NSMutableArray array]; [self.itemModels enumerateObjectsUsingBlock:^(MTGridSelectModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { [array addObject:@(idx)]; }]; [self changeItemStateAtIndexs:array state:state changeByInner:NO]; } - (void)layoutSubviews { [super layoutSubviews]; CGRect frame = self.frame; frame.size = self.collectionView.frame.size; self.frame = frame; } - (void)createAndLayoutItemContentViews { MTGridSelectConfig *config = self.config; if (self.setupConfigBlock) { self.setupConfigBlock(config); } UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init]; flowLayout.minimumLineSpacing = config.rowSpacing; flowLayout.minimumInteritemSpacing = config.columnSpacing; CGSize itemSize = config.itemSize; if (CGSizeEqualToSize(itemSize, CGSizeZero)) { itemSize.width = (config.contentWidth - config.contentInset.left - config.contentInset.right - config.columnSpacing * (config.maxColumn - 1)) / config.maxColumn; itemSize.height = config.itemHeight > 0 ? config.itemHeight : itemSize.width * config.itemRatio; } flowLayout.itemSize = itemSize; CGFloat contentHeight = config.contentInset.top + config.contentInset.bottom + (itemSize.height + config.rowSpacing) * (self.itemModels.count / config.maxColumn + 1) - config.rowSpacing; CGFloat contentWidth = config.contentInset.left + config.contentInset.right + (itemSize.width + config.columnSpacing) * config.maxColumn - config.columnSpacing; self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, config.contentWidth, contentHeight) collectionViewLayout:flowLayout]; [self layoutSubviews]; self.collectionView.showsVerticalScrollIndicator = YES; self.collectionView.showsHorizontalScrollIndicator = YES; self.collectionView.contentSize = CGSizeMake(contentWidth, contentHeight); self.collectionView.backgroundColor = [UIColor clearColor]; self.collectionView.contentInset = config.contentInset; self.collectionView.dataSource = self; self.collectionView.delegate = self; [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:kItemContentViewCellReuseIdentifier]; [self addSubview:self.collectionView]; [self.collectionView reloadData]; dispatch_async(dispatch_get_main_queue(), ^{ // 默认选中 [self selectItemAtIndexs:self.config.defaultSelectIndexs]; }); } #pragma mark - UICollectionViewDelegate - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { [collectionView deselectItemAtIndexPath:indexPath animated:NO]; [self changeItemViewStateAtIndex:indexPath.item]; } #pragma mark - UICollectionViewDataSource - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { return 1; } - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return self.itemModels.count; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { UICollectionViewCell *itemContentViewCell = [collectionView dequeueReusableCellWithReuseIdentifier:kItemContentViewCellReuseIdentifier forIndexPath:indexPath]; MTGridSelectModel *itemModel = self.itemModels[indexPath.item]; if (self.didSetupItemContentViewBlock) { [itemContentViewCell.contentView removeSubviews]; UIView *itemView = self.didSetupItemContentViewBlock(itemContentViewCell.contentView, itemModel.model); itemModel.itemView = itemView; // 默认禁掉交互 itemView.userInteractionEnabled = NO; [itemContentViewCell.contentView addSubview:itemView]; } return itemContentViewCell; } @end