ZZFLEX-界面构建从未如此简单

ZZFLEX是一个iOS UI敏捷开发框架,基于UIKit实现,主要包含经常使用控件的链式API拓展、一个数据驱动的列表框架、一个事件处理队列。现已支持使用ZZUIHelper自动生成UI代码。git

git地址:github.com/tbl00c/ZZFL…github

功能模块

目前ZZFLEX主要包含如下5个功能模块:设计模式

  • UIView+ZZFLEX:为UIKit中经常使用的控件增长了链式API拓展;
  • ZZFlexibleLayoutViewController:基于UICollectionView的数据驱动的列表页框架;
  • ZZFLEXAngel:ZZFlexibleLayoutViewController核心逻辑抽离出的一个列表控制器,更加轻量,支持tableView、collectionView;
  • ZZFLEXEditExtension:为ZZFLEXAngel和ZZFlexibleLayoutViewController增长了处理编辑类页面的能力;
  • ZZFLEXRequestQueue:一个事件处理队列,设计的初衷为解决复杂页面多接口请求时、UI刷新顺序的问题。

UIView+ZZFLEX

UIView+ZZFLEX主要是为UIkit中的经常使用控件增长了链式API的拓展,引入它后,咱们能够直接为viewaddButton、addLabel、addImageView等等,而后经过链式API能够更加连贯快捷的进行控件的属性设置、Masonry布局和事件处理。缓存

以给视图添加button为例说明,一般咱们的作法是这样的:性能优化

UIButton *button = [[UIButton alloc] init];
// 设置样式
[button setBackgroundColor:[UIColor orangeColor]];
[button setTitle:@"hello" forState:UIControlStateNormal];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button setTitle:@"world" forState:UIControlStateHighlighted];
[button setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];
// 设置事件(须要额外的事件处理方法)
[button addTarget:self action:@selector(buttonDown) forControlEvents:UIControlEventTouchDown];
[button addTarget:self action:@selector(buttonUp) forControlEvents:UIControlEventTouchUpInside];
// 设置圆角和边线
[button.layer setMasksToBounds:YES];
[button.layer setCornerRadius:3.0f];
[button.layer setBorderWidth:1.0f];
[button.layer setBorderColor:[UIColor redColor].CGColor];
// 添加到视图
[self.view addSubview:button];
// 设置约束
[button mas_makeConstraints:^(MASConstraintMaker *make) {
    make.size.mas_equalTo(CGSizeMake(80, 35));
    make.center.mas_equalTo(0);
}];
复制代码

使用UIView+ZZFLEX后,你能够这样写:bash

UIButton *button = self.view.addButton(1001)
// 设置样式
.title(@"hello").titleColor([UIColor blackColor])
.titleHL(@"world").titleColorHL([UIColor redColor])
// 设置圆角和边线
.cornerRadius(3.0f).border(1, [UIColor redColor])
// 设置约束
.masonry(^(MASConstraintMaker *make) {
    make.size.mas_equalTo(CGSizeMake(80, 35));
    make.center.mas_equalTo(0);
})
// 设置事件
.eventBlock(UIControlEventTouchDown, ^(UIButton *sender){
    NSLog(@"touch down");
})
.eventBlock(UIControlEventTouchUpInside, ^(UIButton *sender){
    NSLog(@"touch up");
})
.view;
复制代码

以上能够很直观的看出,一样的功能,代码行数有原先的33行缩减到了20行,而且写起来更加顺畅。若是咱们须要持有这个button指针,只需在最后加一个.view便可。框架

UIView+ZZFLEX是使用的是Objective-C的泛型实现的,因此能够无视继承关系、随意顺序设置控件的属性。异步

如需对控件的属性进行编辑,能够这样写:ide

button.zz_make.frame(CGRectMake(0, 0, 100, 40)).title(@"hi").titleColor(@"how are u");
复制代码

如需单首创建一个控件,不添加到视图上:布局

UIButton *button = UIButton.zz_create(1001).title(@"hello").titleHL(@"world");
复制代码

目前,UIView+ZZFLEX已添加链式API的控件有:

  • UIView
  • UIImageView
  • UILabel
  • UIControl
  • UITextField
  • UIButton
  • UISwitch
  • UIScrollView
  • UITextView
  • UITableView
  • UICollectionView

ZZFlexibleLayoutViewController

ZZFlexibleLayoutViewController继承自UIViewController,是一个基于collectionView实现的数据驱动的列表页框架,可大幅下降复杂列表界面实现和维护的难度。

咱们知道collectionView在使用过程当中,各类代理方法重复度高,而且越复杂的界面各类代理方法中的代码就越复杂、越难以维护,一旦设计很差还容易出现性能问题。不少设计模式和第三方库从代码结构和数据缓存等各个角度作出了优化,也取得了必定的效果。但ZZFLEX不一样的是,它将从根源解决这一个问题。

使用ZZFlexibleLayoutViewController,咱们几乎丝绝不用实现collectionView的各类代理方法。它使得列表页的构建就如同拼图通常,只须要一件件的add须要的模块,便可绘制出咱们想要的界面:

// 清空全部数据
self.clear();

// 添加section
self.addSection(ZZFDGoodSectionTypeHeader)
// section样式设置
.sectionInsets(UIEdgeInsetsMake(15, 15, 15, 15))
.minimumLineSpacing(15).minimumInteritemSpacing(15)
// section背景色支持
.backgrounColor([UIColor orangeColor]);
    
// 添加cell
self.addCell(NSStringFromClass([ZZFDGoodAreaCell class]))
.toSection(ZZFDGoodSectionTypeHeader).withDataModel(listModel)
// 内部事件,也可经过delegate的模式
// .delegate(self)
.eventAction(^ id(NSInteger eventType, id data) {
    NSLog(@"cell 内部事件,类型:%ld", eventType);
    return nil;
})
// cell选中事件
.selectedAction(^ (id data) {
    NSLog(@"cell 选中事件");
});

// 刷新界面
[self reloadView];
复制代码

在ZZFlexibleLayoutViewController中,咱们不在使用sectionIndex/indexPath肯定section/cell的位置,转而使用更惟一的sectionTag/viewTag代替。由于前者本质上是一个很不肯定的数据、它会随着界面的变化而发生改变,不少与tableView/collectionView相关的崩溃也都与此有关。

说完了collectionView容器,再说容器里的元素。和以前不一样的是,全部添加到ZZFlexibleLayoutViewController中的cell、header、footer须要额外实现一个协议—ZZFlexibleLayoutViewProtocol:

/**
 * 全部要加入ZZFlexibleLayoutViewController、ZZFLEXAngel的view/cell都要实现此协议
 * 
 * 除获取大小/高度两个方法须要二选一以外,其他均可按需选择实现
 */

@protocol ZZFlexibleLayoutViewProtocol <NSObject>

@optional;
/**
 * 获取cell/view大小,除非手动调用update方法,不然只调用一次,与viewHeightByDataModel二选一
 */
+ (CGSize)viewSizeByDataModel:(id)dataModel;
/**
 * 获取cell/view高度,除非手动调用update方法,不然只调用一次,与viewSizeByDataModel二选一
 */
+ (CGFloat)viewHeightByDataModel:(id)dataModel;


/**
 *  设置cell/view的数据源
 */
- (void)setViewDataModel:(id)dataModel;

/**
 *  设置cell/view的delegate对象
 */
- (void)setViewDelegate:(id)delegate;

/**
 *  设置cell/view的actionBlock
 */
- (void)setViewEventAction:(id (^)(NSInteger actionType, id data))eventAction;

/**
 * 当前视图的indexPath,所在section元素数(目前仅cell调用)
 */
- (void)viewIndexPath:(NSIndexPath *)indexPath sectionItemCount:(NSInteger)count;

@end
复制代码

cell/view实现这个协议的目的是,方便框架层统一处理collectionView中的的各类代理方法,而且也有一些性能优化方面的考虑,想计算大小/高度的那个方法,实际会作大小/高度的缓存,即在不手动调用刷新方法时,自始至终只会在添加时调用一次,你们能够放心使用。

目前主要支持的功能:

添加 插入 获取 批量添加 批量插入 批量获取 编辑 删除 清空子数据 更新高度
section ✔️ ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
cell ✔️ ✔️ ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
header/footer ✔️ ✔️ ✔️ ✔️

使用方法简述:

NSInteger sectionTag = 1001;
NSInteger cellTag = 100101;
NSArray *data = @[@"1", @"2", @"3", @"4"];
    
// 插入section,条件能够是beforeSection、afterSection、toIndex
self.insertSection(sectionTag).beforeSection(1001).minimumInteritemSpacing(5).minimumLineSpacing(5);
    
// 批量添加cell
self.addCells(@"ACell").withDataModelArray(data).toSection(sectionTag).delegate(self.dataModel).viewTag(cellTag);
    
// 批量插入cell,条件能够是beforeCell、afterCell、toIndex
self.insertCells(@"BCell").withDataModelArray(data).toSection(sectionTag).beforeCell(cellTag);
    
// 获取并编辑section
self.sectionForTag(sectionTag).backgrounColor([UIColor yellowColor]);
    
// 删除指定section中的某一个cell
self.sectionForTag(sectionTag).deleteCellByTag(cellTag);
// 批量删除指定section中的符合条件的cell
self.sectionForTag(sectionTag).deleteAllCellsByTag(cellTag);
    
// 删除全局符合条件的cell,条件能够是cellTag、dataModel、viewCclassName、indexPath
self.deleteCell.byViewTag(cellTag);
// 批量删除全局符合条件的cell,条件能够是cellTag、dataModel、viewCclassName
self.deleteCells.byDataModel(data[0]);
    
// 更新指定section中items的高度
self.sectionForTag(sectionTag).update();
// 全局更新指定条件的cell,条件能够是cellTag、dataModel、viewCclassName、indexPath
self.updateCell.atIndexPath([NSIndexPath indexPathForRow:0 inSection:0]);
    
// 清空指定section中的items
self.sectionForTag(sectionTag).clear();
// 清空指定section中的cells,保留headerFooter
self.sectionForTag(sectionTag).clearCells();
复制代码

ZZFLEXAngel

ZZFlexibleLayoutViewController为列表页的开发带来的优异的拓展性和可维护性,但它是一个VC级别的实现,在一些业务场景下仍是不够灵活的。

ZZFLEXAngel是ZZFlexibleLayoutViewController核心思想和设计提炼而成的一个“列表控制中心”,它与页面和列表控件是彻底解耦的。

使用它,咱们只需经过任意collectionView或tableView来初始化一个ZZFLEXAngel实例(本质是将列表页的dataSource和delegate指向ZZFLEXAngel或其子类的实例),而后就能够经过这个实例、和ZZFlexibleLayoutViewController中同样,使用那些好用的API了。

// 建立列表视图
UITableView *tableView = self.view.addTableView(1)
.frame(self.view.bounds)
.backgroundColor([UIColor colorGrayBG])
.tableFooterView([UIView new])
.view;

// 根据列表视图初始化angel,hostView支持UITableView和UICollectionView
ZZFLEXAngel *angel = [[ZZFLEXAngel alloc] initWithHostView:self.tableView];

// 添加列表元素
angel.addSection(1);
angel.addCell(@"ACell").toSection(1);

// 刷新列表
[tableView reloadData];

复制代码

ZZFLEXEditExtension

此拓展使得ZZFlexibleLayoutViewController和ZZFLEXAngel具备了处理编辑页面的能力,其主要原理为规范了编辑类页面处理流程,并使用一个额外的模型来控制它:

初始标准数据模型 -> 经ZZFLEXEditModel封装的数据 -> UI展示 -> 用户编辑 -> 输入合法性判断 -> 标准数据模型 -> 导出数据

详见Demo。

ZZFLEXRequestQueue

一些复杂的页面中会存在多个异步数据请求(net、db等),然而同时发起的异步请求,其结果的返回顺序是不肯定的,这样会致使UI展现顺序的不肯定性,不少状况下这是咱们不但愿看到的。

ZZFLEXRequestQueue的核心思想是“将一次数据请求的过程封装成对象”,它能够保证在此业务场景下,按队列顺序加载展现UI。

详见Demo。

如何使用

一、直接导入方式

将项目下载到本地后,把ZZFlexibleLayoutFramework拖入到你的项目中,便可正常使用。

二、CocoaPods方式

Pod 'ZZFLEX', :git => 'git@github.com:tbl00c/ZZFLEX.git'
复制代码

其余

使用中的任何问题,欢迎提issure,也可与我交流:libokun@126.com

相关文章
相关标签/搜索