ZZFLEX是一個iOS UI敏捷開發框架,基於UIKit實現,主要包含經常使用控件的鏈式API拓展、一個數據驅動的列表框架、一個事件處理隊列。現已支持使用ZZUIHelper自動生成UI代碼。git
git地址:github.com/tbl00c/ZZFL…github
目前ZZFLEX主要包含如下5個功能模塊:設計模式
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的控件有:
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();
複製代碼
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];
複製代碼
此拓展使得ZZFlexibleLayoutViewController和ZZFLEXAngel具備了處理編輯頁面的能力,其主要原理爲規範了編輯類頁面處理流程,並使用一個額外的模型來控制它:
初始標準數據模型 -> 經ZZFLEXEditModel封裝的數據 -> UI展示 -> 用戶編輯 -> 輸入合法性判斷 -> 標準數據模型 -> 導出數據
詳見Demo。
一些複雜的頁面中會存在多個異步數據請求(net、db等),然而同時發起的異步請求,其結果的返回順序是不肯定的,這樣會致使UI展現順序的不肯定性,不少狀況下這是咱們不但願看到的。
ZZFLEXRequestQueue的核心思想是「將一次數據請求的過程封裝成對象」,它能夠保證在此業務場景下,按隊列順序加載展現UI。
詳見Demo。
將項目下載到本地後,把ZZFlexibleLayoutFramework拖入到你的項目中,便可正常使用。
Pod 'ZZFLEX', :git => 'git@github.com:tbl00c/ZZFLEX.git'
複製代碼
使用中的任何問題,歡迎提issure,也可與我交流:libokun@126.com