The common refresh is the open source MJRefresh, which must be a library that many developers are familiar with. The author adopts the method of inheritance, and different levels have different functions and UI display, which is simple and convenient to use.


Mj_header and mj_footer are two associated objects for UIScrollView. Examples of usage by MJ author Li Mingjie are as follows:

  • The drop-down refresh
__weak typeof(self) weakSelf = self; The self. The tableView. Mj_header = [MJRefreshHeader headerWithRefreshingBlock: ^ {[weakSelf refreshAction]; / / here can do request network operations.}]. [self.tableView.mj_header endRefreshing];Copy the code
  • Pull up to load more
__weak typeof(self) weakSelf = self; self.tableView.mj_footer = [MJRefreshBackNormalFooter footerWithRefreshingBlock:^{ [weakSelf footerRefreshAction]; // Request more data}]; // The refresh can be terminated in different ways depending on the result of the request. [self.tableView.mj_footer endRefreshing]; [self.tableView.mj_footer endRefreshingWithNoMoreData];Copy the code

This is just an example. The authors of MJ provide headers and footers for a variety of UI and interaction options.

Usually this can be used directly according to the author’s Demo example, but I always feel not good. Just want to be able to encapsulate (mainly lazy, want to save some things).

Let’s start with the basic requirements: a list of TableViews that request 20 pieces of data per page (note: different companies may have different numbers per page, but this is just an example), a drop-down refresh to request the first page of data, and a pull-up load to request the next page of data. If the data on the next page is still 20, it is considered that there is still data and the footr is refreshed at the end of the normal state. The next pull-up load will normally request data from the next page. If the data load is less than the number of data items on a page (20), then there is no more data, and the footer is refreshed at the end of the page with no more data, which will not work when the puller is loaded.

What I want is that when I make an external call, I just want to know when to trigger to ask for more refreshes and loads, and nothing else.

My current implementation is: write a category for UITableView (same for UICollectionView). UIScrollView can also be refreshed by pull-down, but not by pull-up loading. Two methods are written, which are pull-down refresh and pull-up load calls. Two associated objects were added: the number of pieces of data per page and a pull-up callback block for setting the footer after loading more. Example code is as follows:

#define WeakSelf __weak typeof(self) weakSelf = self;typedef void(^FooterConfigBlock)(NSInteger newDataCount); typedef void(^RefreshActionBlock)(FooterConfigBlock footerConfig); @interface UITableView (Refresh) /** Number of entries per page */ @property (nonatomic,strong)NSNumber *pageCount; /** Set the footer callback */ @property (nonatomic,copy)void(^footerConfigBlock)(NSInteger newCount); /** refresh the header @param refreshBlock refreshBlock"FooterConfigBlock"External call when the request to pull down the data of the strip of data in, let the method inside the footer to set. Eg: If there is no data in the pull-down refresh, you can simply remove the footer. */ - (void)normalHeaderRefreshingActionBlock:(RefreshActionBlock)refreshBlock; /** Footer refresh loads more @param footerRefreshBlock loads more callback. There's a callback block"FooterConfigBlock"External call when the request to pull down the data of the strip of data in, let the method inside the footer to set. Eg: If the pull-up load returns less than the number of Settings items per page, the data is considered complete and the footer can be set to no more data. */ - (void)backNormalFooterRefreshingActionBlock:(RefreshActionBlock)footerRefreshBlock; @end @implementation UITableView (Refresh)#pragma mark -- Associated object ----------------
- (void)setPageCount:(NSNumber *)pageCount
{
    objc_setAssociatedObject(self, @selector(setPageCount:), pageCount, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSNumber *)pageCount
{
    return objc_getAssociatedObject(self, @selector(setPageCount:));
}

- (void)setFooterConfigBlock:(void (^)(NSInteger))footerConfigBlock
{
    objc_setAssociatedObject(self, @selector(setFooterConfigBlock:), footerConfigBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (void (^)(NSInteger))footerConfigBlock
{
    return objc_getAssociatedObject(self, @selector(setFooterConfigBlock:));
}


#pragma mark --header Refresh ----------------- (void) normalHeaderRefreshingActionBlock: RefreshActionBlock refreshBlock {/ / if the external call sets the amount of data entry page not pageCount. Set a default value here. self.pageCount = [self.pageCountintegerValue] > 0 ? self.pageCount : @(20); WeakSelf // Assigns the external block to the associated object, if the external needs internal footer and header end refresh processing, you can pass the block in. self.footerConfigBlock = ^(NSInteger newCount) { [weakSelf handleEndRefreshing:newCount]; }; self.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{ refreshBlock(weakSelf.footerConfigBlock); }]; }#pragma mark --footer refresh ----------------- (void) backNormalFooterRefreshingActionBlock: RefreshActionBlock footerRefreshBlock {/ / similarly set a default page data entry self. PageCount = [self.pageCountintegerValue] > 0 ? self.pageCount : @(20);
    WeakSelf
    self.footerConfigBlock = ^(NSInteger newCount) {
        [weakSelf handleEndRefreshing:newCount];
    };
    
    self.mj_footer = [MJRefreshBackNormalFooter footerWithRefreshingBlock:^{
        footerRefreshBlock(weakSelf.footerConfigBlock);
    }];
}

- (void)handleEndRefreshing:(NSInteger)count
{
    if (self.mj_header.isRefreshing) {
        [self.mj_header endRefreshing];
        [self.mj_footer endRefreshing];
    }
    
    if (count < [self.pageCount integerValue]) {
        [self.mj_footer endRefreshingWithNoMoreData];
    }else{ [self.mj_footer endRefreshing]; }}#pragma Mark -- End refresh -----// If the outside world wants to handle the end refresh itself, it can add other end refresh methods to the tabelView. - (void)beginRefreshing {if(! self.mj_header)return;
    [self.mj_header beginRefreshing];
}

- (void)endRefrehing
{
    if (self.mj_header) {
        [self.mj_header endRefreshing];
    }
    if (self.mj_footer) {
        [self.mj_footer endRefreshing];
    }
}
@end
Copy the code

External calls are as follows:

- (void)configTableView { WeakSelf [self.tableView normalHeaderRefreshingActionBlock:^(FooterConfigBlock _Nonnull FooterConfig) {weakself. page = 1; // Pull up refresh trigger request first page data.  [weakSelf requestData:^(NSInteger count) { weakSelf.dataCount = count; [weakSelf.tableView reloadData]; FooterConfig (count); footerConfig(count);  } failCallBack:^{ [weakSelf.tableView endRefrehing]; }]; }]; [self.tableView backNormalFooterRefreshingActionBlock:^(FooterConfigBlock _Nonnull footerConfig) { [weakSelf requestData:^(NSInteger count) { weakSelf.dataCount += count; [weakSelf.tableView reloadData]; FooterConfig (count); footerConfig(count);  } failCallBack:^{ [weakSelf.tableView endRefrehing]; }]; }]; [self.tableView beginRefreshing]; } - (void)requestData:(void(^)(NSInteger count))successCallBack failCallBack:(void(^)(void))failCallBack { Dispatch_after (dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{if (self.page > 5) {
            successCallBack(0);
        }else{
            successCallBack(20);
        }
        self.page += 1;
    });
}

Copy the code

The above is a simple encapsulation example of its own. MJRefresh provides a variety of headers and footers that can be customized and encapsulated to suit your business or product requirements.

The above is my summary of some use, if there are mistakes, please also criticize and correct. Thanks!!