看下界面, 這是類似于索引的頁面, 只不過木有右側(cè)索引條的布局. 如果想了解通訊錄索引的,請移步iOS - 高仿通訊錄之商品索引排序搜索.
提供思路如下:
- 分析界面及接口
- 用 MVC 設計模式來實現(xiàn)(其實核心點都在下面5)
- 創(chuàng)建內(nèi)外層 Model 并綁定兩者 Model
- 兩者 Cell 布局的實現(xiàn) (便于后期界面的快速更改)
- 在外層控制器內(nèi)進行邏輯操作并請求數(shù)據(jù)的分區(qū)及每個分區(qū)行數(shù)的處理.
5.1 創(chuàng)建一個保存數(shù)據(jù)的數(shù)組timeList, 這個數(shù)組是外層列表數(shù)組(分區(qū)時間數(shù)組)
5.2 拿到數(shù)組后, 就可以考慮分區(qū)數(shù)目及當前分區(qū)下 cell 數(shù)目
5.3 創(chuàng)建header的界面及數(shù)據(jù)
5.4 找到相對應的分區(qū)去帶回內(nèi)層數(shù)組 - 跳轉(zhuǎn)控制器內(nèi)層數(shù)組的傳值簡單實現(xiàn).
Step1. 分析界面及接口
首先我們先分析這個界面:
很明顯這是一個 tableView 的多分區(qū)多cell的布局.
這樣就好辦許多,截取一個分區(qū)來做說明.
很明顯的能看出來, 這必須只能是 Model 套 Model 了. 分析下接口:
Step2. 用 MVC 設計模式來實現(xiàn).
大致思路有了,那我們接著該整理 MVC 了.
簡單來說, 就是創(chuàng)建兩套 MVC: 外層盤點記錄的 MVC 與 內(nèi)層盤點詳情的 MVC(其中內(nèi)層的還包括外層盤點記錄下的每個當前分區(qū)下的記錄 cell 詳情).
看起來是兩套 MVC, 由于我們內(nèi)層的兩個數(shù)組里字典數(shù)據(jù)是一樣的模型, 我就共用了一套內(nèi)層 M, 其實是三部分的交錯使用.
看個點擊分區(qū)跳轉(zhuǎn)到盤點詳情的 MVC 界面:
Step3. 創(chuàng)建內(nèi)外層 Model 并綁定兩者 Model
由于只提供思路,就只放核心部分代碼.
先創(chuàng)建內(nèi)層的 子Model(YYPRecordDetailsModel)就和一般正常的 Model 創(chuàng)建一樣就好,
// 時間
@property (nonatomic, copy) NSString *dotime;
// 商品名稱
@property (nonatomic, copy) NSString *commodityName;
// 商品金額
@property (nonatomic, assign) float commodityAmt;
// 實際盤點數(shù)量
@property (nonatomic, assign) NSInteger inventoryNum;
// 庫存數(shù)量
@property (nonatomic, assign) NSInteger stockNum;
接著創(chuàng)建外層的 一級Model(YYPInventoryRecordModel), 除了幾個基本單元素外, 兩個內(nèi)層數(shù)組是子 Model 不要忘了要放進去.
// 詳情全部數(shù)據(jù)
@property (nonatomic, strong) NSArray *inventoryList;
// 虧盈數(shù)據(jù)
@property (nonatomic, strong) NSArray *inventoryList2;
最后在外層 Model 的. m 里實現(xiàn)兩者的綁定.
+ (NSDictionary *)objectClassInArray {
return @{@"inventoryList" : [YYPRecordDetailsModel class], @"inventoryList2" : [YYPRecordDetailsModel class]};
}
Step4. 兩者 Cell 布局的實現(xiàn)
頁面都是根據(jù)產(chǎn)品和 UI 確定, 我們單獨寫UITableViewCell, 好處就是便于后期界面的快速更改.
可以根據(jù)自己的界面來寫. 我這里就記錄下 Model 賦值. 一定切記,選擇相對應的 Model. 我這里展示分區(qū)下的 cell 就相對應的是子Modle.
// model賦值
- (void)setModel:(YYPRecordDetailsModel *)model {
_model = model;
// 商品名稱
self.commodityName.text = [NSString stringWithFormat:@"%@", model.commodityName];
// 單價
self.commodityAmt.text = [NSString stringWithFormat:@"¥%.2f", model.commodityAmt];
// 盈虧
if (model.inventoryNum >= model.stockNum) {
self.result.textColor = YYPGrayTitleColor;
if (model.inventoryNum > model.stockNum) {
self.result.text = [NSString stringWithFormat:@"+%ld", (model.inventoryNum - model.stockNum)];
} else {
self.result.text = @"0";
}
} else if (model.inventoryNum < model.stockNum) { // 虧
self.result.textColor = YYPRedTitleColor;
self.result.text = [NSString stringWithFormat:@"-%ld", (model.stockNum - model.inventoryNum)];
}
}
Step5. 在外層控制器內(nèi)進行邏輯操作并請求數(shù)據(jù)的分區(qū)及每個分區(qū)行數(shù)的處理.
其實這里就是重點核心部分了!我要劃重點啦~
5.1 看盤點記錄界面, 就是一個TableView, 那么我們創(chuàng)建一個保存數(shù)據(jù)的數(shù)組timeList, 這個數(shù)組是外層列表數(shù)組(分區(qū)時間數(shù)組).
@property (nonatomic, strong) NSMutableArray *timeList;
- (NSMutableArray *)timeList {
if (!_timeList) {
_timeList = [NSMutableArray array];
}
return _timeList;
}
PS: 切記!!!千萬不要再創(chuàng)建內(nèi)層數(shù)組,容易把自己繞糊涂, 有了外層數(shù)組,需要內(nèi)層數(shù)組數(shù)據(jù)時是可以通過外層數(shù)組 timeList 去獲取的.譬如行數(shù)據(jù):model.inventoryList2[indexPath.row]
5.2 拿到數(shù)組后, 就可以考慮分區(qū)數(shù)目及當前分區(qū)下 cell 數(shù)目
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
self.tableView.mj_footer.hidden = self.timeList.count == 0;
return self.timeList.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
YYPInventoryRecordModel *model = self.timeList[section];
return model.inventoryList2.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
YYPInventoryRecordDetailCell *detailCell = [YYPInventoryRecordDetailCell cellWithTableView:tableView];
if (self.timeList.count) { // 有時候傳值為nil
YYPInventoryRecordModel *model = self.timeList[indexPath.section];
YYPRecordDetailsModel *detailModel = model.inventoryList2[indexPath.row];
detailCell.model = detailModel;
}
return detailCell;
}
#pragma mark - UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
return YYPInventoryRecordDetailCellHeight;
}
5.3 這個時候盤點記錄的 cell詳情出來了, 接著考慮header的界面及數(shù)據(jù).
在viewForHeaderInSection
里創(chuàng)建
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section ;
賦值取當前一級 Model 下字段: [[_timeList objectAtIndex:section] valueForKey:@"dotime"]];
dotime.text = [NSString stringWithFormat:@"%@", [[_timeList objectAtIndex:section] valueForKey:@"dotime"]];
分區(qū)Header內(nèi)容也是由外層 Model 賦值的, 返回每個分區(qū)的內(nèi)容self.timeList[section]
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return self.timeList[section];
}
5.4 由于我們還有下個跳轉(zhuǎn)頁面,同時還是取當前接口數(shù)據(jù), 這個時候我們就要找到相對應的分區(qū)去跳轉(zhuǎn)即可.
在cell 點擊跳轉(zhuǎn)相對來說方便的多,因為這個有系統(tǒng)方法didSelectRowAtIndexPath
.只需要找到相對應分區(qū)self.timeList[indexPath.section]
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
YYPInventoryRecordModel *model = self.timeList[indexPath.section];
YYPRecordDetailsController *vc = [[YYPRecordDetailsController alloc] init];
vc.inventoryList = model.inventoryList;
[self.navigationController pushViewController:vc animated:YES];
}
若是header 上也要實現(xiàn)按鈕跳轉(zhuǎn), 可以在viewForHeaderInSection
方法里的按鈕上加個標記與header的分區(qū)section一致, 然后找到相對應分區(qū)self.timeList[sender.tag]就好.
inIcon.tag = section;
實現(xiàn)跳轉(zhuǎn)方法
- (void)btnClick:(UIButton *)sender {
// 用 tag 來標記section
YYPInventoryRecordModel *model = self.timeList[sender.tag];
YYPRecordDetailsController *vc = [[YYPRecordDetailsController alloc] init];
vc.inventoryList = model.inventoryList;
[self.navigationController pushViewController:vc animated:YES];
}
5.5 最后就是請求了.
拿到最外層的數(shù)組數(shù)據(jù)就好.
[weakSelf.timeList removeAllObjects];
NSArray *currentPageArray = [YYPInventoryRecordModel loadInventoryRecordInfoFromJson:json[@"data"]];
[weakSelf.timeList addObjectsFromArray:currentPageArray];
至于上拉加載更多數(shù)據(jù)/下拉刷新新數(shù)據(jù) 及 網(wǎng)絡不佳狀態(tài)重新加載獲取請求這些都是按自己項目需求添加的. 這里就不一一展示了.
Step6. 跳轉(zhuǎn)控制器內(nèi)層數(shù)組的傳值簡單實現(xiàn).
這其實就是一個簡單的正常的 MVC. 就是不需要請求接口,就是正向傳值帶回來一個數(shù)組.
.h 里露出一個屬性便于傳值.
// 詳情全部數(shù)據(jù)
@property (nonatomic, strong) NSArray *inventoryList;
在. m 里創(chuàng)建一個保存接收數(shù)據(jù)的可變數(shù)據(jù)
// 詳情全部數(shù)據(jù)
@property (nonatomic, strong) NSMutableArray *goodList;
需要加載inventoryList數(shù)據(jù)帶回到goodList.
#pragma mark - 懶加載
- (NSMutableArray *)goodList {
if (!_goodList) {
_goodList = [NSMutableArray array];
[_goodList addObjectsFromArray:_inventoryList];
}
return _goodList;
}
簡單的Table view data source方法:
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.goodList.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
YYPRecordDetailsCell *cell = [YYPRecordDetailsCell cellWithTableView:tableView];
if (self.goodList.count) { // 有時候傳值為nil
YYPRecordDetailsModel *model = self.goodList[indexPath.row];
cell.model = model;
}
return cell;
}
這個時候,完整測試下效果吧:
如果需要看訂單詳情頁那種Model 套 Model 的請移步: Model套Model之iOS模型閑聊