ChainedDroplist
链式Droplist,提供基本的DataSource和Delegate封装
尽量做到最大化的Cell扩展
欢迎提交issues和PRs,帮助改进
在最近的项目中,经常遇到下拉/上拉列表(droplist)的需求,共性比较多,但是会有细微的差异;当然首选是用UITableView
,但是如果每个droplist都创建个datasource
、delegate
,也未免也太麻烦了;所以抽出点时间封装了一个简单的链式Droplist,主要满足以下几种需求:
- 使用链式编程(在一个方法中完成droplist cell组装、展示、选择的处理)
- 提供可选的droplist hostview(并不是所有droplist都直接加载在KeyWindow上)
- 提供可选的tap rotation icon(点击、展示droplist应该伴随着icon的旋转,不是吗?)
- 提供可选的droplist baseView(droplist应该在点击view的下沿或上沿进行展开)
- 如果上方/下发展示空间不足,将自动调整展开方向(相信我,虽然用户不在意,但是测试总会遇到这个bug)
- 默认展示5行,如果展示空间不足,将自动**-1**直至满足展示条件(小屏用户的体验也要考虑)
- Cell支持可最大化扩展,目前建议使用继承方式(你永远不知道下一个设计师会设计出什么)
先来看个简单的说明:
先看使用方法,有一个基本思路:
- (void)showDroplist:(UIView *)baseView icon:(UIView *)icon hostView:(UIView *)hostView
{
[[[[[ChainedDroplistView alloc] initWithConfig:^(ChainedDroplistView *droplist) {
droplist.hostView = self.view; /* 展示droplist的父view,默认为Window */
droplist.baseView = baseView; /* 用于确定 droplist 的 top/bottom */
droplist.rotationView = icon; /* 展示droplist的同时做旋转的view */
droplist.cellHeight = 60; /* 默认Cell height */
droplist.datas = [self createTestDatas]; /* 创建 cell datas */
}] registCustomerCellsWithConfig:^(UITableView *tableView) {
/* 绑定 Cell Identifier */
[tableView registerClass:ChainedDroplistBaseCell.class forCellReuseIdentifier:kChainedDroplistBaseCellIdentifier];
}] show] /* 调用 show 之后会执行展示动画 */
processAfterSelected:^(NSInteger index) {
/* 用户选中某个 Cell 后会执行该 block */
NSLog(@"U have selected index -> [%@]", @(index));
}];
}
代码结构
基于UITableView
封装,通过ChainedDroplistModelProtocol
和ChainedDroplistCellProtocol
来关联Cell和Model
ChainedDroplistModelProtocol
- 提供
registerClass:forCellReuseIdentifier:
的identifier - 可以直接继承
ChainedDroplistBaseModel
,重写- (NSString *)strCellIdentifier
方法提供自定义identifier
Cell
configCellWithModel:
在每个tableView:cellForRowAtIndexPath:
方法中都会调用,该方法可以用于根据model更新Cell
关键代码:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger index = indexPath.row;
NSAssert(index < self.cellDatas.count, @"index[%@] beyonds the max count[%@] of datas", @(index), @(self.cellDatas.count));
// 根据 ChainedDroplistModelProtocol strCellIdentifier 获取指定Cell
id<ChainedDroplistModelProtocol> model = self.cellDatas[index];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:model.strCellIdentifier];
NSAssert([cell conformsToProtocol:@protocol(ChainedDroplistCellProtocol)],
@"cell[%@] from identifier[%@] must conforms protocol [%@]",
cell, model.strCellIdentifier, NSStringFromProtocol(@protocol(ChainedDroplistCellProtocol)));
UITableViewCell <ChainedDroplistCellProtocol> * droplistCell = (UITableViewCell <ChainedDroplistCellProtocol> *)cell;
if ([droplistCell respondsToSelector:@selector(configCellWithModel:)]) {
// 刷新Cell
[droplistCell configCellWithModel:model];
}
return droplistCell;
}
ChainedDroplistBaseCell
中initWithStyle:reuseIdentifier:
调用了setupUI
、setupConstraints
用于设置UI和约束,可以直接继承ChainedDroplistBaseCell
,重写setupUI
、setupConstraints
来完成Customer cell的定义
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.selectionStyle = UITableViewCellSelectionStyleNone;
[self setupUI];
[self setupConstraints];
}
return self;
}
identifier的声明和定义
- 在Model中通过
FOUNDATION_EXPORT NSString *const identifier
声明identifier
- 在Cell中定义相关的
identifier
:NSString *const identifier=@"identifier"
这么做只是为了通过简单的 identifier
搜索就可以找出 cell 和对应的 model
示例
想了解的同学可以参考示例中的使用方法
cd Example/
- 运行
pod update --no-repo-update
打开 ChainedDroplist.xcworkspace/
为了尽可能说明ChainDroplist
的设计初衷,示例中列举了比较详细的使用场景,包括:
- 默认场景:向下展开,5行可见
- 向下展示空间不足:根据
hostView
和cellHeight
来计算可视空间,如果下方空间不足会改为向上展示 rotationView
用于在展开droplist时做同步旋转- 如果 上方、下方 空间均不足以展示5行,主动计算最少可展示行数并展示
- 通过继承
ChainedDroplistBaseCell
、ChainedDroplistBaseModel
来实现自定义样式
需求
安装
ChainedDroplist 通过 CocoaPods 提供使用。要安装它,只需在你的 Podfile 中添加以下行
pod 'ChainedDroplist'
作者
seuzxh, [email protected]
许可协议
ChainedDroplist 在 MIT 许可协议下提供。有关更多信息,请参阅 LICENSE 文件。