iOS小技能:整合下拉重新整理控制元件 & 實現無感知上拉載入更多
持續創作,加速成長!這是我參與「掘金日新計劃 · 10 月更文挑戰」的第18天,點選檢視活動詳情
引言
需求:由於訊息列表,資料量比較大,為了提升使用者體驗,需採用分頁載入顯示資料
案例:iOS零售版ERP APP增加支付獎勵訊息通知
通知資訊(定時xx點;歷史訊息可查)
2021-04-29 尊敬的商家,您參與的xxx激勵金活動,昨日參與成功10筆,共獲得激勵金1元!
![]()
I 整合下/上拉重新整理控制元件
1.1 定義相關分頁屬性
- 分頁屬性 ```objectivec
@property (nonatomic , assign) NSInteger pageNum;//當前頁碼 @property (nonatomic , assign) NSInteger pageCount;// 總頁數 @property (nonatomic , assign) BOOL isfooterRereshing; // 每頁顯示數... ```
- VM中的事件和資料屬性
```objectivec @property (nonatomic,strong) NSMutableArray *datas;
@property (nonatomic,strong) RACSubject *reloadSubject;
@property (nonatomic,strong) RACSubject *ShowNoviewSubject;
@property (nonatomic,strong) RACSubject *hidenNoviewSubject;
```
1.2 監聽下拉和上拉事件
- VC 監聽和處理下拉和上拉事件 ```objectivec _tableView.mj_footer = [MJRefreshBackNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(footerRereshing)]; _tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(headerRereshing)];
``` - 處理上拉載入資料事件
```objectivec /* 用於標誌下拉動作/ @property (nonatomic , assign) BOOL isfooterRereshing;
-
(void)footerRereshing { self.isfooterRereshing = YES;
if ((_pageNum + 1) > _pageCount) {
[self.tableView.mj_footer endRefreshingWithNoMoreData]; return;
}
_pageNum = _pageNum + 1; [self doorRequest];
}
- 處理下拉重新整理資料事件
objectivec
- (void)headerRereshing
{
self.isfooterRereshing = NO;
[_doorArr removeAllObjects];// 移除資料,可請求成功之後,再移除
_pageNum = 1;
[self doorRequest];
}
```
1.3 請求資料的處理
請求成功和失敗都要關閉重新整理檢視 ```objectivec [weakSelf.vcView.tableView.mj_footer endRefreshing]; [weakSelf.vcView.tableView.mj_header endRefreshing];
完成處理的程式碼
objectivec
- (void)doorRequest
{
//暫無資料
if (self.viewModel.datas.count == 0) {
[self.viewModel.ShowNoviewSubject sendNext:QCTLocal(@"no_data")];
}else{
[self.viewModel.hidenNoviewSubject sendNext:QCTLocal(@"")];
}
if(![UserInfoModel.shareUserInfoModel ispayStoreId]){
// [self showHUDMessage:@"請先進件"];
// 顯示暫無資料
return;
}
NSString *post = [NSString stringWithFormat:@"%@%@",currentPayHost,@""];
NSMutableDictionary *params = [NSMutableDictionary dictionary];
//111850
// [params setValue:@"" forKey:@"sid"];
[params setValue:UserInfoModel.shareUserInfoModel.store.payStoreId forKey:@"sid"];
[params setValue:[[NSNumber numberWithInteger:self.pageNum]description] forKey:@"page"];
[params setValue:kPageSize forKey:@"pageSize"];
__weak __typeof__(self) weakSelf = self;
[QCTNetworkHelper Post:post parameters:params success:^(NSDictionary* responseObj) {
NSDictionary *data = nil;
if([responseObj.allKeys containsObject:@"data"]){
data = responseObj[@"data"];
}else{
[self showHUDMessage:@"資料異常!"];
// [SVProgressHUD showInfoWithStatus:@"資料異常!"];
return;// 獲取資料失敗
}
if([data.allKeys containsObject:@"data"]){
data = responseObj[@"data"];
}else{
// [SVProgressHUD showInfoWithStatus:@"資料異常!"];
[self showHUDMessage:@"資料異常!"];
return;// 獲取資料失敗
}
NSMutableArray* tmparrresult = [ERPTradeRewardReportDto mj_objectArrayWithKeyValuesArray:data[@"data"]];
if(self.isfooterRereshing){
[weakSelf.viewModel.datas addObjectsFromArray:tmparrresult];
}else{
weakSelf.viewModel.datas = tmparrresult ;
}
[weakSelf.vcView.tableView reloadData];
weakSelf.pageCount = [responseObj[@"data"][@"pageCount"] integerValue];
weakSelf.pageNum = [responseObj[@"data"][@"page"] integerValue];
[weakSelf.vcView.tableView.mj_footer endRefreshing];
[weakSelf.vcView.tableView.mj_header endRefreshing];
if (weakSelf.viewModel.datas.count == 0) {
[weakSelf.viewModel.ShowNoviewSubject sendNext:QCTLocal(@"no_data")];
}else{
[weakSelf.viewModel.hidenNoviewSubject sendNext:QCTLocal(@"no_data")];
}
} failure:^(NSError * _Nonnull error) {
[QCTNetworkHelper showLoading_failed_please_try_again_laterBlock];
[self.vcView.tableView.mj_footer endRefreshing];
[self.vcView.tableView.mj_header endRefreshing];
} bizFailure:^(id _Nonnull responseObj) {
[self.vcView.tableView.mj_footer endRefreshing];
[self.vcView.tableView.mj_header endRefreshing];
[QCTNetworkHelper showresponseObjmessage:responseObj];
} isShowLoadingDataGif:YES];
}
```
II iOS實現無感知上拉載入更多
2.1 思路1:UITableViewDataSourcePrefetching
```objectivec // this protocol can provide information about cells before they are displayed on screen.
@protocol UITableViewDataSourcePrefetching
@required
// indexPaths are ordered ascending by geometric distance from the table view
- (void)tableView:(UITableView )tableView prefetchRowsAtIndexPaths:(NSArray
@optional
// indexPaths that previously were considered as candidates for pre-fetching, but were not actually used; may be a subset of the previous call to -tableView:prefetchRowsAtIndexPaths:
- (void)tableView:(UITableView )tableView cancelPrefetchingForRowsAtIndexPaths:(NSArray
@end
```
2.2 實現思路2:通過 KVO 去監聽 scrollView 的 contentOffset 變化
MJRefreshAutoFooter 有個專門的屬性triggerAutomaticallyRefreshPercent 去做自動重新整理
```objectivec
import "MJRefreshFooter.h"
NS_ASSUME_NONNULL_BEGIN
@interface MJRefreshAutoFooter : MJRefreshFooter /* 是否自動重新整理(預設為YES) / @property (assign, nonatomic, getter=isAutomaticallyRefresh) BOOL automaticallyRefresh;
/* 當底部控制元件出現多少時就自動重新整理(預設為1.0,也就是底部控制元件完全出現時,才會自動重新整理) / @property (assign, nonatomic) CGFloat appearencePercentTriggerAutoRefresh MJRefreshDeprecated("請使用triggerAutomaticallyRefreshPercent屬性");
/* 當底部控制元件出現多少時就自動重新整理(預設為1.0,也就是底部控制元件完全出現時,才會自動重新整理) / @property (assign, nonatomic) CGFloat triggerAutomaticallyRefreshPercent;
/** 自動觸發次數, 預設為 1, 僅在拖拽 ScrollView 時才生效,
如果為 -1, 則為無限觸發 */ @property (nonatomic) NSInteger autoTriggerTimes; @end
```
III 重新整理控制元件的適配
- 上拉載入:安全區域距離適配 ```objectivec
define k_safeAreaInsetsBottom [UIApplication sharedApplication].delegate.window.safeAreaInsets.bottom
define isIphoneX isHasSafeAreaInsets
define k_ignoredScrollViewContentInsetBottom (isIphoneX?k_safeAreaInsetsBottom:0)
_vcView.tableView.mj_footer.ignoredScrollViewContentInsetBottom = k_ignoredScrollViewContentInsetBottom;
```
-
下拉重新整理適配:present 半屏適配、設定下拉樣式 http://blog.csdn.net/z929118967/article/details/104477314
-
分頁併發適配: 方式1. 升級MJRefresh到3.7.5版本
Fix/duplicated async method -> Installing MJRefresh 3.7.5 (was 3.3.1)
方式2. 使用自動重新整理控制元件MJRefreshNormalHeader->MJRefreshAutoNormalFooter
see also
案例:新浪微博API(獲取使用者微博資料) http://download.csdn.net/download/u011018979/20689654
- 整合下拉重新整理控制元件:下拉重新整理 HWHomeTableViewController
- 獲取未讀訊息數: HWHomeTableViewController
- 封裝標題按鈕:HWTitleButton
更多內容請關注公眾號:iOS逆向
- iOS小技能:UITableView的適配 (iOS10/iOS14/iOS16.0)
- iOS小技能:和uni-app、unity的融合方案
- iOS小技能:iOS15崩潰排查技巧(symbolicatecrash符號化分析問題、匯出和隱藏符號)
- iOS小技能:【intercept the HTTP/HTTPS requests 】利用NSURLProtocol 攔截請求
- iOS小技能: tweak 整合CocoaAsyncSocket(建連、斷開、重連、心跳、通用請求)
- iOS小技能:iOS13 證件掃描 & 文字識別API
- iOS小技能:整合下拉重新整理控制元件 & 實現無感知上拉載入更多
- iOS小技能:程式碼觸發button的點選事件、快速找到按鈕action方法
- iOS小技能:撥號、發郵件、簡訊、應用間跳轉
- iOS小技能:鏈式程式設計在iOS開發中的應用
- iOS小技能:iOS14 讀取使用者剪下板資料彈出提示的相容方案
- iOS小技能:因境外IP無法訪問導致 App 被拒的解決方案
- iOS小技能:RSA簽名、驗籤、加密、解密的原理
- iOS小技能:Xcode14新特性(適配)
- iOS小技能:Socket基礎知識
- iOS小技能:SKU檢視搭建
- iOS小技能: 日曆的使用(案例:兩個時間的比較、獲取最近30天的資料)
- iOS小技能:1. iOS 實現json資料提交 2. 對同一個URL的多次請求進行資料快取 3. 檢查網路狀態
- iOS小技能:使用正則表示式對聊天記錄的關鍵詞進行監控
- iOS小技能:去掉/新增導航欄黑邊(iOS13適配)