一个优雅、简洁的 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+
在 Podfile 中添加:
pod 'ZBFancyCollectionView'然后运行:
pod install#import "ZBFancyCollectionView.h"
- (UICollectionView *)collectionView {
if (!_collectionView) {
// 使用 FlowLayout
_collectionView = [UICollectionView flowLayout];
// 或使用 FancyLayout(支持悬停)
// _collectionView = [UICollectionView fancyLayoutWithStyle:ZBFancyCollectionViewStylePlain];
}
return _collectionView;
}import ZBFancyCollectionView
lazy var collectionView: UICollectionView = {
// 使用 FlowLayout
let cv = UICollectionView.flowLayout()
// 或使用 FancyLayout(支持悬停)
// let cv = UICollectionView.fancyLayoutWithStyle(.plain)
return cv
}()[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");
}];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")
}[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);
});
}];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)")
}
}ZBFancyCollectionViewCell 提供了模板功能,可以在不创建单独的 Cell 类的情况下快速构建 Cell。
// 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");
}];// 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")
}initializeViewBlock: 初始化视图,只在 Cell 首次创建时调用一次updateViewBlock: 更新视图,每次数据更新时调用resetViewBlock: 重置视图,在 Cell 重用前调用layoutSubviewsBlock: 自定义布局,在layoutSubviews时调用
使用 ZBFancyLayout 可以实现 Section Header 悬停效果。
// 创建带悬停效果的 CollectionView
UICollectionView *collectionView = [UICollectionView fancyLayoutWithStyle:ZBFancyCollectionViewStylePlain];
// 或使用自定义样式,指定悬停的 Section
collectionView.fancyLayout.style = ZBFancyCollectionViewStyleCustom;
collectionView.fancyLayout.hoverIndexPath = [NSIndexPath indexPathForItem:0 inSection:0];
collectionView.fancyLayout.hoverOffset = 0; // 悬停偏移量// 创建带悬停效果的 CollectionView
let collectionView = UICollectionView.fancyLayoutWithStyle(.plain)
// 或使用自定义样式
collectionView.fancyLayout.style = .custom
collectionView.fancyLayout.hoverIndexPath = IndexPath(item: 0, section: 0)
collectionView.fancyLayout.hoverOffset = 0ZBFancyCollectionViewStylePlain: Header 会悬停ZBFancyCollectionViewStyleGrouped: Header 不会悬停ZBFancyCollectionViewStyleCustom: 自定义,可指定特定 Section 的 Header 悬停
[self.collectionView zb_replaceSection:@"section1" block:^(ZBCollectionMaker *maker) {
maker.row(@"<title>").model(@{@"text": @"New Content"});
}];[self.collectionView zb_appendSection:@"section1" block:^(ZBCollectionMaker *maker) {
maker.row(@"<title>").model(@{@"text": @"Appended Row"});
}];[self.collectionView zb_appendRowsForSection:@"section1" block:^(ZBCollectionMaker *maker) {
maker.row(@"<title>").model(@{@"text": @"New Row"});
}];// 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;
}
}链式调用构建器,用于配置 Section 和 Row。
section(NSString *key): 创建 SectionsectionHeader(NSString *proto): 配置 Section HeadersectionFooter(NSString *proto): 配置 Section FootercanMove(BOOL canMove): 设置是否允许移动
row(NSString *proto): 创建 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
用于注册 Cell、Header、Footer。
cell(NSString *protoType): 注册 CellheaderView(NSString *protoType): 注册 HeaderfooterView(NSString *protoType): 注册 Footer
每个方法返回 ZBCollectionViewCellConfig,可链式调用:
cls(NSString *clsName): 设置类名nibName(NSString *nibName): 设置 Nib 名称nib(UINib *nib): 设置 Nib 对象
zb_configCollectionView(void (^)(ZBCollectionProtoFactory *)): 配置 CollectionView(注册 Cell 等)zb_configTableView(void (^)(ZBCollectionProtoFactory *)): 兼容方法,等同于zb_configCollectionViewzb_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)
自定义布局类,支持悬停效果。
style: 布局样式(Plain/Grouped/Custom)hoverIndexPath: 悬停的 IndexPath(Custom 样式时使用)hoverOffset: 悬停偏移量
- 线程安全: 本框架不是线程安全的,所有操作应在主线程进行
- Identifier 格式: 建议使用
<>包裹的格式,如@"<title>",便于识别 - 数据更新:
zb_setup会调用reloadData,其他更新方法不会自动刷新,需要手动调用reloadData或使用performBatchUpdates - 内存管理: 注意 Block 中的循环引用,使用
__weak/__strong或 Swift 的[weak self]
查看 Example 目录获取完整示例代码。
欢迎提交 Issue 和 Pull Request!
ZBFancyCollectionView 使用 MIT 许可证。详情请查看 LICENSE 文件。