// // KBSkinDetailVC.m // keyBoard // // 皮肤详情页(UICollectionView 实现) // 结构: // - Section0:顶部大卡片(上图,下方左右两段文案) // - Section1:标签容器 cell(内部再嵌套一个 collectionView 以展示 Cute/Fresh 等标签) // - Section2:区块标题 cell(例如 “Recommended Skin”) // - Section3:推荐皮肤 2 列网格(使用已有 KBSkinCardCell) // #import "KBSkinDetailVC.h" #import #import "UIColor+Extension.h" #import "UICollectionViewLeftAlignedLayout.h" #import "KBSkinDetailHeaderCell.h" #import "KBSkinTagsContainerCell.h" #import "KBSkinCardCell.h" // 已有的 皮肤卡片 cell(用作 2 列网格) #import "KBSkinSectionTitleCell.h" static NSString * const kHeaderCellId = @"kHeaderCellId"; static NSString * const kTagsContainerCellId = @"kTagsContainerCellId"; static NSString * const kSectionTitleCellId = @"kSectionTitleCellId"; static NSString * const kGridCellId = @"kGridCellId"; // 直接复用 KBSkinCardCell typedef NS_ENUM(NSInteger, KBSkinDetailSection) { KBSkinDetailSectionHeader = 0, KBSkinDetailSectionTags, KBSkinDetailSectionTitle, KBSkinDetailSectionGrid, KBSkinDetailSectionCount }; @interface KBSkinDetailVC () @property (nonatomic, strong) UICollectionView *collectionView; // 主列表 @property (nonatomic, copy) NSArray *tags; // 标签数据 @property (nonatomic, copy) NSArray *gridData; // 底部网格数据 @end @implementation KBSkinDetailVC - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; // 简单数据(演示) self.tags = @[ @"Cute", @"Fresh", @"Cute", @"Fresh", @"Cute", @"Fresh" ]; self.gridData = @[ @{ @"title": @"Dopamine" }, @{ @"title": @"Dopamine" }, @{ @"title": @"Dopamine" }, @{ @"title": @"Dopamine" }, @{ @"title": @"Dopamine" }, @{ @"title": @"Dopamine" }, ]; [self.view addSubview:self.collectionView]; [self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.view); }]; } #pragma mark - UICollectionView DataSource - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { return KBSkinDetailSectionCount; } - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { switch (section) { case KBSkinDetailSectionHeader: return 1; // 顶部大卡片 case KBSkinDetailSectionTags: return 1; // 标签容器 case KBSkinDetailSectionTitle: return 1; // 标题 case KBSkinDetailSectionGrid: return self.gridData.count; // 2 列网格 } return 0; } - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { switch (indexPath.section) { case KBSkinDetailSectionHeader: { KBSkinDetailHeaderCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kHeaderCellId forIndexPath:indexPath]; [cell configWithTitle:@"Dopamine" right:@"Download: 1 Million"]; return cell; } case KBSkinDetailSectionTags: { KBSkinTagsContainerCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kTagsContainerCellId forIndexPath:indexPath]; [cell configWithTags:self.tags]; return cell; } case KBSkinDetailSectionTitle: { KBSkinSectionTitleCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kSectionTitleCellId forIndexPath:indexPath]; [cell config:@"Recommended Skin"]; return cell; } case KBSkinDetailSectionGrid: { KBSkinCardCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kGridCellId forIndexPath:indexPath]; NSDictionary *d = self.gridData[indexPath.item]; [cell configWithTitle:d[@"title"] imageURL:nil price:@"20"]; return cell; } } return [UICollectionViewCell new]; } #pragma mark - UICollectionView DelegateFlowLayout - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { CGFloat W = collectionView.bounds.size.width; CGFloat insetLR = 16.0; CGFloat contentW = W - insetLR * 2; switch (indexPath.section) { case KBSkinDetailSectionHeader: { // 高度 = 图片 0.58W + 文案与上下留白(≈56) CGFloat h = contentW * 0.58 + 56; return CGSizeMake(contentW, h); } case KBSkinDetailSectionTags: { CGFloat h = [KBSkinTagsContainerCell heightForTags:self.tags width:W]; return CGSizeMake(contentW, h); } case KBSkinDetailSectionTitle: { return CGSizeMake(contentW, 44); } case KBSkinDetailSectionGrid: { // 2 列 CGFloat spacing = 12.0; CGFloat itemW = floor((contentW - spacing) / 2.0); CGFloat itemH = itemW * 0.75 + 56; // 参考 KBSkinCardCell 内部布局 return CGSizeMake(itemW, itemH); } } return CGSizeZero; } - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { return UIEdgeInsetsMake(12, 16, 12, 16); } - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { return 12.0; } - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { // 网格区需要这个间距,其它区也保持统一 return 12.0; } #pragma mark - Lazy - (UICollectionView *)collectionView { if (!_collectionView) { UICollectionViewFlowLayout *layout = [UICollectionViewFlowLayout new]; layout.scrollDirection = UICollectionViewScrollDirectionVertical; _collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; _collectionView.backgroundColor = [UIColor whiteColor]; _collectionView.dataSource = self; _collectionView.delegate = self; // 注册 cell [_collectionView registerClass:KBSkinDetailHeaderCell.class forCellWithReuseIdentifier:kHeaderCellId]; [_collectionView registerClass:KBSkinTagsContainerCell.class forCellWithReuseIdentifier:kTagsContainerCellId]; [_collectionView registerClass:KBSkinSectionTitleCell.class forCellWithReuseIdentifier:kSectionTitleCellId]; [_collectionView registerClass:KBSkinCardCell.class forCellWithReuseIdentifier:kGridCellId]; } return _collectionView; } @end