// // MySkinVC.m // keyBoard // #import "MySkinVC.h" #import #import "UIColor+Extension.h" #import #import "UIScrollView+KBEmptyView.h" // 统一空态封装(LYEmptyView) #import "MySkinCell.h" static NSString * const kMySkinCellId = @"kMySkinCellId"; @interface MySkinVC () @property (nonatomic, strong) UICollectionView *collectionView; // 列表 @property (nonatomic, strong) UIView *bottomView; // 底部操作条 @property (nonatomic, strong) UILabel *selectedLabel; // 已选择数量 @property (nonatomic, strong) UIButton *deleteButton; // 删除 @property (nonatomic, strong) NSMutableArray *data; // 简单数据源 @property (nonatomic, assign) NSInteger loadCount; // 刷新计数(用于演示空/有数据切换) @property (nonatomic, assign, getter=isEditingMode) BOOL editingMode; // 是否编辑态 @end @implementation MySkinVC - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; // self.title = @"My Skin"; // 标题 // 右上角 Editor/Cancel self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Editor" style:UIBarButtonItemStylePlain target:self action:@selector(onToggleEdit)]; // 数据源初始化为空(演示空态 + 下拉刷新) self.data = [NSMutableArray array]; // 视图 [self.view addSubview:self.collectionView]; [self.view addSubview:self.bottomView]; [self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self.view).offset(KB_NAV_TOTAL_HEIGHT); make.left.right.equalTo(self.view); make.bottom.equalTo(self.view.mas_bottom); }]; [self.bottomView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self.view); make.bottom.equalTo(self.view.mas_safeAreaLayoutGuideBottom); make.height.mas_equalTo(64); }]; // 空态视图(LYEmptyView)统一样式 + 重试按钮 KBWeakSelf [self.collectionView kb_makeDefaultEmptyViewWithImage:nil title:@"暂无皮肤" detail:@"下拉刷新试试" buttonTitle:@"重试" tapHandler:nil buttonHandler:^{ [weakSelf.collectionView.mj_header beginRefreshing]; }]; [self.collectionView kb_setLYAutoShowEnabled:NO]; // 采用手动控制显隐 // 立即按当前数据源状态显示一次空态(首屏就应展示空视图) [self.collectionView kb_endLoadingForEmpty]; // 下拉刷新(演示网络加载 + 空态切换) self.collectionView.mj_header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(fetchData)]; // 首次进入自动刷新 [self.collectionView.mj_header beginRefreshing]; // 初始:非编辑态,隐藏底部 self.bottomView.hidden = YES; } #pragma mark - Data - (void)fetchData { // 模拟网络延迟 1.0s dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.loadCount += 1; // 交替返回:奇数次空数据,偶数次有数据(演示空态/非空切换) [self.data removeAllObjects]; if (self.loadCount % 2 == 0) { for (int i = 0; i < 8; i++) { [self.data addObject:@{ @"title": @"Dopamine" }]; } } [self.collectionView reloadData]; [self.collectionView kb_endLoadingForEmpty]; // 根据数据源显示/隐藏 emptyView [self.collectionView.mj_header endRefreshing]; }); } #pragma mark - Actions - (void)onToggleEdit { self.editingMode = !self.editingMode; // 更新顶部按钮 self.navigationItem.rightBarButtonItem.title = self.isEditingMode ? @"Cancel" : @"Editor"; // 控制底部栏显隐 self.bottomView.hidden = !self.isEditingMode; // 列表进入/退出多选 self.collectionView.allowsMultipleSelection = self.isEditingMode; // 直接刷新可见 cell,确保切换后立刻出现/隐藏 markView for (UICollectionViewCell *c in self.collectionView.visibleCells) { if (![c isKindOfClass:MySkinCell.class]) continue; MySkinCell *cell = (MySkinCell *)c; cell.editing = self.isEditingMode; NSIndexPath *ip = [self.collectionView indexPathForCell:cell]; BOOL selected = [[self.collectionView indexPathsForSelectedItems] containsObject:ip]; [cell updateSelected:selected]; } // 再做一次 reload 保守刷新(防止 offscreen cell) [self.collectionView reloadData]; // 清空选择并刷新底部文案 for (NSIndexPath *ip in [self.collectionView indexPathsForSelectedItems]) { [self.collectionView deselectItemAtIndexPath:ip animated:NO]; } [self updateBottomUI]; } - (void)onDelete { // 根据选中项删除 NSArray *selected = [[self.collectionView indexPathsForSelectedItems] sortedArrayUsingSelector:@selector(compare:)]; if (selected.count == 0) return; // 批量更新,先改数据,再删 UI [self.collectionView performBatchUpdates:^{ NSMutableIndexSet *set = [NSMutableIndexSet indexSet]; for (NSIndexPath *ip in selected) { [set addIndex:ip.item]; } [self.data removeObjectsAtIndexes:set]; [self.collectionView deleteItemsAtIndexPaths:selected]; } completion:^(BOOL finished) { [self updateBottomUI]; // 根据当前数据源显隐空视图(删除到 0 条时应显示空态) [self.collectionView kb_endLoadingForEmpty]; }]; } - (void)updateBottomUI { NSInteger count = self.collectionView.indexPathsForSelectedItems.count; self.selectedLabel.text = [NSString stringWithFormat:@"Selected: %ld Skins", (long)count]; BOOL enable = count > 0; self.deleteButton.enabled = enable; if (enable) { self.deleteButton.backgroundColor = [UIColor colorWithHex:KBColorValue]; [self.deleteButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; self.deleteButton.layer.borderColor = [UIColor colorWithHex:KBColorValue].CGColor; } else { self.deleteButton.backgroundColor = [UIColor colorWithHex:0xF2F2F2]; [self.deleteButton setTitleColor:[UIColor colorWithHex:0xC8C8C8] forState:UIControlStateNormal]; self.deleteButton.layer.borderColor = [UIColor colorWithHex:0xE6E6E6].CGColor; } } #pragma mark - UICollectionView - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return self.data.count; } - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { MySkinCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kMySkinCellId forIndexPath:indexPath]; NSDictionary *d = self.data[indexPath.item]; [cell configWithTitle:d[@"title"] image:nil]; cell.editing = self.isEditingMode; // 控制是否显示选择圆点 // 同步选中状态(复用时) BOOL selected = [[collectionView indexPathsForSelectedItems] containsObject:indexPath]; [cell updateSelected:selected]; return cell; } - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { if (!self.isEditingMode) { // 非编辑态:可在此进入详情,当前示例不处理 [collectionView deselectItemAtIndexPath:indexPath animated:YES]; return; } MySkinCell *cell = (MySkinCell *)[collectionView cellForItemAtIndexPath:indexPath]; [cell updateSelected:YES]; [self updateBottomUI]; } - (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath { if (!self.isEditingMode) return; MySkinCell *cell = (MySkinCell *)[collectionView cellForItemAtIndexPath:indexPath]; [cell updateSelected:NO]; [self updateBottomUI]; } - (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath { if (![cell isKindOfClass:MySkinCell.class]) return; MySkinCell *c = (MySkinCell *)cell; c.editing = self.isEditingMode; // 保证滚动出现的新 cell 同步编辑态 BOOL selected = [[collectionView indexPathsForSelectedItems] containsObject:indexPath]; [c updateSelected:selected]; } #pragma mark - Lazy - (UICollectionView *)collectionView { if (!_collectionView) { UICollectionViewFlowLayout *layout = [UICollectionViewFlowLayout new]; CGFloat inset = 16; CGFloat spacing = 12; CGFloat W = UIScreen.mainScreen.bounds.size.width; CGFloat itemW = floor((W - inset * 2 - spacing) / 2.0); CGFloat itemH = itemW * 0.82f; // 接近截图比例 layout.itemSize = CGSizeMake(itemW, itemH); layout.minimumInteritemSpacing = spacing; layout.minimumLineSpacing = spacing; layout.sectionInset = UIEdgeInsetsMake(12, inset, 12, inset); _collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; _collectionView.backgroundColor = [UIColor whiteColor]; _collectionView.dataSource = self; _collectionView.delegate = self; _collectionView.allowsMultipleSelection = NO; // 初始 [_collectionView registerClass:MySkinCell.class forCellWithReuseIdentifier:kMySkinCellId]; } return _collectionView; } - (UIView *)bottomView { if (!_bottomView) { _bottomView = [UIView new]; _bottomView.backgroundColor = [UIColor whiteColor]; _bottomView.layer.shadowColor = [UIColor colorWithWhite:0 alpha:0.06].CGColor; _bottomView.layer.shadowOpacity = 1; _bottomView.layer.shadowOffset = CGSizeMake(0, -2); [_bottomView addSubview:self.selectedLabel]; [_bottomView addSubview:self.deleteButton]; [self.selectedLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(_bottomView).offset(16); make.centerY.equalTo(_bottomView); }]; [self.deleteButton mas_makeConstraints:^(MASConstraintMaker *make) { make.right.equalTo(_bottomView).offset(-16); make.centerY.equalTo(_bottomView); make.width.mas_equalTo(92); make.height.mas_equalTo(36); }]; } return _bottomView; } - (UILabel *)selectedLabel { if (!_selectedLabel) { _selectedLabel = [UILabel new]; _selectedLabel.textColor = [UIColor colorWithHex:0x666666]; _selectedLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightMedium]; _selectedLabel.text = @"Selected: 0 Skins"; } return _selectedLabel; } - (UIButton *)deleteButton { if (!_deleteButton) { _deleteButton = [UIButton buttonWithType:UIButtonTypeSystem]; [_deleteButton setTitle:@"Delete" forState:UIControlStateNormal]; _deleteButton.titleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightSemibold]; _deleteButton.layer.cornerRadius = 18; _deleteButton.layer.borderWidth = 1; _deleteButton.clipsToBounds = YES; [_deleteButton addTarget:self action:@selector(onDelete) forControlEvents:UIControlEventTouchUpInside]; // 初始禁用态样式 _deleteButton.enabled = NO; _deleteButton.backgroundColor = [UIColor colorWithHex:0xF2F2F2]; [_deleteButton setTitleColor:[UIColor colorWithHex:0xC8C8C8] forState:UIControlStateNormal]; _deleteButton.layer.borderColor = [UIColor colorWithHex:0xE6E6E6].CGColor; } return _deleteButton; } @end