继续创作,加快成长!这是我参加「日新方案 10 月更文应战」的第18天,点击检查活动详情

导言

需求:因为音讯列表,数据量比较大,为了提高用户体会,需采用分页加载显现数据

iOS小技能:集成下拉刷新控件 & 实现无感知上拉加载更多

事例:iOS零售版ERP APP增加支付奖赏音讯通知

iOS小技能:集成下拉刷新控件 & 实现无感知上拉加载更多

通知信息(守时xx点;前史音讯可查)

2021-04-29 尊敬的商家,您参加的xxx鼓励金活动,昨日参加成功10笔,共取得鼓励金1元!

iOS小技能:集成下拉刷新控件 & 实现无感知上拉加载更多
iOS小技能:集成下拉刷新控件 & 实现无感知上拉加载更多

I 集成下/上拉改写控件

1.1 界说相关分页特点

  • 分页特点

@property (nonatomic , assign) NSInteger pageNum;//当前页码
@property (nonatomic , assign) NSInteger pageCount;// 总页数
@property (nonatomic , assign) BOOL isfooterRereshing;
// 每页显现数...
  • VM中的事情和数据特点
@property (nonatomic,strong)  NSMutableArray *datas;
@property (nonatomic,strong)  RACSubject *reloadSubject;
@property (nonatomic,strong)  RACSubject *ShowNoviewSubject;
@property (nonatomic,strong)  RACSubject *hidenNoviewSubject;

1.2 监听下拉和上拉事情

  • VC 监听和处理下拉和上拉事情
        _tableView.mj_footer = [MJRefreshBackNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(footerRereshing)];
        _tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(headerRereshing)];
  • 处理上拉加载数据事情
/** 用于标志下拉动作*/
@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];
}
  • 处理下拉改写数据事情
- (void)headerRereshing
{
    self.isfooterRereshing = NO;
    [_doorArr removeAllObjects];// 移除数据,可恳求成功之后,再移除
    _pageNum = 1;
    [self doorRequest];
}

1.3 恳求数据的处理

恳求成功和失利都要封闭改写视图

        [weakSelf.vcView.tableView.mj_footer endRefreshing];
        [weakSelf.vcView.tableView.mj_header endRefreshing];

完结处理的代码

- (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

// this protocol can provide information about cells before they are displayed on screen.
@protocol UITableViewDataSourcePrefetching <NSObject>
@required
// indexPaths are ordered ascending by geometric distance from the table view
- (void)tableView:(UITableView *)tableView prefetchRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths;
@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<NSIndexPath *> *)indexPaths;
@end

2.2 实现思路2:通过 KVO 去监听 scrollView 的 contentOffset 变化

MJRefreshAutoFooter 有个专门的特点triggerAutomaticallyRefreshPercent 去做主动改写

iOS小技能:集成下拉刷新控件 & 实现无感知上拉加载更多

#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 改写控件的适配

  1. 上拉加载:安全区域距离适配
#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;
  1. 下拉改写适配:present 半屏适配、设置下拉款式 blog.csdn.net/z929118967/…

  2. 分页并发适配: 方法1. 升级MJRefresh到3.7.5版本 Fix/duplicated async method -> Installing MJRefresh 3.7.5 (was 3.3.1) 方法2. 使用主动改写控件MJRefreshNormalHeader->MJRefreshAutoNormalFooter

see also

事例:新浪微博API(获取用户微博数据) download.csdn.net/download/u0…

  • 集成下拉改写控件:下拉改写 HWHomeTableViewController
  • 获取未读音讯数: HWHomeTableViewController
  • 封装标题按钮:HWTitleButton

更多内容请关注公众号:iOS逆向