Skip to content

k373379320/ZBFancyCollectionView

Repository files navigation

ZBFancyCollectionView

CI Status Version License Platform

一个优雅、简洁的 iOS UICollectionView 配置和管理框架。通过链式调用和 Block 回调,让 CollectionView 的使用变得简单高效。

✨ 特性

  • 🎯 链式调用 API - 流畅的链式语法,代码更简洁易读
  • 📦 零配置 Cell - 支持使用 ZBFancyCollectionViewCell 模板,无需创建单独的 Cell 类
  • 🎨 灵活布局 - 支持任意尺寸的 Cell 布局,自动流式排列
  • 📌 悬停 Header - 支持 Section Header 悬停效果
  • 🔄 动态更新 - 支持动态添加、替换、追加 Section 和 Row
  • 🎭 多种布局样式 - Plain、Grouped、Custom 三种布局样式
  • 🔧 易于扩展 - 支持自定义 Cell、Header、Footer
  • 📱 兼容性好 - 支持 iOS 12.0+,同时支持 Objective-C 和 Swift

📋 要求

  • iOS 12.0+
  • Xcode 12.0+
  • Objective-C 或 Swift 5.0+

📦 安装

CocoaPods

Podfile 中添加:

pod 'ZBFancyCollectionView'

然后运行:

pod install

🚀 快速开始

1. 创建 CollectionView

Objective-C

#import "ZBFancyCollectionView.h"

- (UICollectionView *)collectionView {
    if (!_collectionView) {
        // 使用 FlowLayout
        _collectionView = [UICollectionView flowLayout];
        
        // 或使用 FancyLayout(支持悬停)
        // _collectionView = [UICollectionView fancyLayoutWithStyle:ZBFancyCollectionViewStylePlain];
    }
    return _collectionView;
}

Swift

import ZBFancyCollectionView

lazy var collectionView: UICollectionView = {
    // 使用 FlowLayout
    let cv = UICollectionView.flowLayout()
    
    // 或使用 FancyLayout(支持悬停)
    // let cv = UICollectionView.fancyLayoutWithStyle(.plain)
    
    return cv
}()

2. 注册 Cell 和 Header/Footer

Objective-C

[self.collectionView zb_configCollectionView:^(ZBCollectionProtoFactory *config) {
    // 注册 Cell
    config.cell(@"<title>").cls(@"TitleCell");
    config.cell(@"<image>").cls(@"ImageCell");
    
    // 注册 Header
    config.headerView(@"<header>").cls(@"SectionHeaderView");
    
    // 注册 Footer
    config.footerView(@"<footer>").cls(@"SectionFooterView");
    
    // 使用 Nib
    // config.cell(@"<custom>").nibName(@"CustomCell");
}];

Swift

collectionView.zb_configCollectionView { config in
    // 注册 Cell
    _ = config.cell("<title>").cls("TitleCell")
    _ = config.cell("<image>").cls("ImageCell")
    
    // 注册 Header
    _ = config.headerView("<header>").cls("SectionHeaderView")
    
    // 注册 Footer
    _ = config.footerView("<footer>").cls("SectionFooterView")
}

3. 配置数据

Objective-C

[self.collectionView zb_setup:^(ZBCollectionMaker *maker) {
    // 创建 Section
    maker.section(@"section1");
    
    // 配置 Section Header
    maker.sectionHeader(@"<header>")
        .model(@{@"title": @"Section 1"});
    
    // 添加 Row
    maker.row(@"<title>")
        .model(@{@"text": @"Hello World"})
        .itemSize(CGSizeMake(100, 44));
    
    maker.row(@"<image>")
        .model(@{@"url": @"https://example.com/image.jpg"})
        .itemSize(CGSizeMake(200, 150));
    
    // 配置点击事件
    maker.row(@"<title>")
        .model(@{@"text": @"Click Me"})
        .selectBlock(^(id model) {
            NSLog(@"Clicked: %@", model);
        });
}];

Swift

collectionView.zb_setup { maker in
    // 创建 Section
    _ = maker.section("section1")
    
    // 配置 Section Header
    _ = maker.sectionHeader("<header>")
        .model(["title": "Section 1"])
    
    // 添加 Row
    _ = maker.row("<title>")
        .model(["text": "Hello World"])
        .itemSize(CGSize(width: 100, height: 44))
    
    _ = maker.row("<image>")
        .model(["url": "https://example.com/image.jpg"])
        .itemSize(CGSize(width: 200, height: 150))
    
    // 配置点击事件
    _ = maker.row("<title>")
        .model(["text": "Click Me"])
        .selectBlock { model in
            print("Clicked: \(model)")
        }
}

📖 详细用法

使用 FancyCell 模板(无需创建 Cell 类)

ZBFancyCollectionViewCell 提供了模板功能,可以在不创建单独的 Cell 类的情况下快速构建 Cell。

Objective-C

// 1. 注册
[self.collectionView zb_configCollectionView:^(ZBCollectionProtoFactory *config) {
    config.cell(@"<empty>").cls(@"ZBFancyCollectionViewCell");
}];

// 2. 配置
[self.collectionView zb_setup:^(ZBCollectionMaker *maker) {
    maker.row(@"<empty>")
        .itemSize(CGSizeMake(kScreenWidth, 98))
        .initializeViewBlock(^(ZBFancyCollectionViewCell *cell) {
            // 初始化视图(只执行一次)
            cell.contentView.backgroundColor = [UIColor colorWithHexString:@"F5F5F5"];
            
            UILabel *label = [[UILabel alloc] init];
            label.textAlignment = NSTextAlignmentCenter;
            label.layer.cornerRadius = 4;
            label.layer.masksToBounds = YES;
            label.backgroundColor = [UIColor whiteColor];
            label.textColor = [UIColor colorWithHexString:@"#B3B3B3"];
            label.font = [UIFont systemFontOfSize:13];
            [cell.contentView addSubview:label];
            [label mas_makeConstraints:^(MASConstraintMaker *make) {
                make.left.offset(10);
                make.right.offset(-10);
                make.top.bottom.offset(0);
            }];
            
            // 设置更新 Block
            cell.updateViewBlock = ^(ZBFancyCollectionViewCell *cell, id data) {
                label.text = data;
            };
        })
        .model(@"Empty State");
}];

Swift

// 1. 注册
collectionView.zb_configCollectionView { config in
    _ = config.cell("<empty>").cls("ZBFancyCollectionViewCell")
}

// 2. 配置
collectionView.zb_setup { maker in
    _ = maker.row("<empty>")
        .itemSize(CGSize(width: UIScreen.main.bounds.width, height: 98))
        .initializeViewBlock { (cell: ZBFancyCollectionViewCell) in
            // 初始化视图
            cell.contentView.backgroundColor = UIColor(hexString: "F5F5F5")
            
            let label = UILabel()
            label.textAlignment = .center
            label.layer.cornerRadius = 4
            label.layer.masksToBounds = true
            label.backgroundColor = .white
            label.textColor = UIColor(hexString: "#B3B3B3")
            label.font = UIFont.systemFont(ofSize: 13)
            cell.contentView.addSubview(label)
            label.snp.makeConstraints { make in
                make.left.equalTo(10)
                make.right.equalTo(-10)
                make.top.bottom.equalTo(0)
            }
            
            // 设置更新 Block
            cell.updateViewBlock = { cell, data in
                label.text = data as? String
            }
        }
        .model("Empty State")
}

ZBFancyCollectionViewCell 的 Block 说明

  • initializeViewBlock: 初始化视图,只在 Cell 首次创建时调用一次
  • updateViewBlock: 更新视图,每次数据更新时调用
  • resetViewBlock: 重置视图,在 Cell 重用前调用
  • layoutSubviewsBlock: 自定义布局,在 layoutSubviews 时调用

悬停 Header

使用 ZBFancyLayout 可以实现 Section Header 悬停效果。

Objective-C

// 创建带悬停效果的 CollectionView
UICollectionView *collectionView = [UICollectionView fancyLayoutWithStyle:ZBFancyCollectionViewStylePlain];

// 或使用自定义样式,指定悬停的 Section
collectionView.fancyLayout.style = ZBFancyCollectionViewStyleCustom;
collectionView.fancyLayout.hoverIndexPath = [NSIndexPath indexPathForItem:0 inSection:0];
collectionView.fancyLayout.hoverOffset = 0; // 悬停偏移量

Swift

// 创建带悬停效果的 CollectionView
let collectionView = UICollectionView.fancyLayoutWithStyle(.plain)

// 或使用自定义样式
collectionView.fancyLayout.style = .custom
collectionView.fancyLayout.hoverIndexPath = IndexPath(item: 0, section: 0)
collectionView.fancyLayout.hoverOffset = 0

布局样式

  • ZBFancyCollectionViewStylePlain: Header 会悬停
  • ZBFancyCollectionViewStyleGrouped: Header 不会悬停
  • ZBFancyCollectionViewStyleCustom: 自定义,可指定特定 Section 的 Header 悬停

动态更新数据

替换整个 Section

[self.collectionView zb_replaceSection:@"section1" block:^(ZBCollectionMaker *maker) {
    maker.row(@"<title>").model(@{@"text": @"New Content"});
}];

追加 Section

[self.collectionView zb_appendSection:@"section1" block:^(ZBCollectionMaker *maker) {
    maker.row(@"<title>").model(@{@"text": @"Appended Row"});
}];

追加 Row 到指定 Section

[self.collectionView zb_appendRowsForSection:@"section1" block:^(ZBCollectionMaker *maker) {
    maker.row(@"<title>").model(@{@"text": @"New Row"});
}];

支持 Cell 移动

// 1. 在配置时设置 canMove
[self.collectionView zb_setup:^(ZBCollectionMaker *maker) {
    maker.section(@"section1");
    maker.canMove(YES);
    maker.row(@"<title>").model(@{@"text": @"Movable"});
}];

// 2. 在 Cell 上添加长按手势
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] 
    initWithTarget:self action:@selector(handleLongPress:)];
[cell addGestureRecognizer:longPress];

- (void)handleLongPress:(UILongPressGestureRecognizer *)gesture {
    CGPoint location = [gesture locationInView:self.collectionView];
    NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:location];
    
    switch(gesture.state) {
        case UIGestureRecognizerStateBegan:
            [self.collectionView beginInteractiveMovementForItemAtIndexPath:indexPath];
            break;
        case UIGestureRecognizerStateChanged:
            [self.collectionView updateInteractiveMovementTargetPosition:location];
            break;
        case UIGestureRecognizerStateEnded:
            [self.collectionView endInteractiveMovement];
            break;
        default:
            [self.collectionView cancelInteractiveMovement];
            break;
    }
}

🔧 API 参考

ZBCollectionMaker

链式调用构建器,用于配置 Section 和 Row。

Section 相关

  • section(NSString *key): 创建 Section
  • sectionHeader(NSString *proto): 配置 Section Header
  • sectionFooter(NSString *proto): 配置 Section Footer
  • canMove(BOOL canMove): 设置是否允许移动

Row 相关

  • row(NSString *proto): 创建 Row

Row 配置方法

  • itemSize(CGSize size): 设置 Cell 尺寸
  • model(id model): 设置数据模型
  • tag(NSString *tag): 设置标签
  • selectBlock(void (^)(id)): 设置点击回调
  • configureBlock(void (^)(id)): 设置配置回调
  • initializeViewBlock(void (^)(ZBFancyCollectionViewCell *)): 设置初始化 Block(仅 FancyCell)
  • configureSEL(SEL selector): 设置配置方法选择器
  • itemSizeSEL(SEL selector): 设置尺寸计算方法选择器
  • bundle(NSBundle *bundle): 设置 Bundle

ZBCollectionProtoFactory

用于注册 Cell、Header、Footer。

  • cell(NSString *protoType): 注册 Cell
  • headerView(NSString *protoType): 注册 Header
  • footerView(NSString *protoType): 注册 Footer

每个方法返回 ZBCollectionViewCellConfig,可链式调用:

  • cls(NSString *clsName): 设置类名
  • nibName(NSString *nibName): 设置 Nib 名称
  • nib(UINib *nib): 设置 Nib 对象

UICollectionView 扩展方法

  • zb_configCollectionView(void (^)(ZBCollectionProtoFactory *)): 配置 CollectionView(注册 Cell 等)
  • zb_configTableView(void (^)(ZBCollectionProtoFactory *)): 兼容方法,等同于 zb_configCollectionView
  • zb_setup(void (^)(ZBCollectionMaker *)): 设置数据(会调用 reloadData
  • zb_replaceSection(NSString *tag, void (^)(ZBCollectionMaker *)): 替换 Section(不调用 reloadData
  • zb_appendSection(NSString *tag, void (^)(ZBCollectionMaker *)): 追加 Section(不调用 reloadData
  • zb_appendRowsForSection(NSString *tag, void (^)(ZBCollectionMaker *)): 追加 Row 到指定 Section(不调用 reloadData

ZBFancyLayout

自定义布局类,支持悬停效果。

  • style: 布局样式(Plain/Grouped/Custom)
  • hoverIndexPath: 悬停的 IndexPath(Custom 样式时使用)
  • hoverOffset: 悬停偏移量

⚠️ 注意事项

  1. 线程安全: 本框架不是线程安全的,所有操作应在主线程进行
  2. Identifier 格式: 建议使用 <> 包裹的格式,如 @"<title>",便于识别
  3. 数据更新: zb_setup 会调用 reloadData,其他更新方法不会自动刷新,需要手动调用 reloadData 或使用 performBatchUpdates
  4. 内存管理: 注意 Block 中的循环引用,使用 __weak/__strong 或 Swift 的 [weak self]

📝 示例项目

查看 Example 目录获取完整示例代码。

🤝 贡献

欢迎提交 Issue 和 Pull Request!

📄 许可证

ZBFancyCollectionView 使用 MIT 许可证。详情请查看 LICENSE 文件。

👤 作者

[email protected]

🔗 相关链接

About

ZBFancyCollectionView

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •  

Languages