淺談對MJRefresh(上)下拉重新整理控制元件的理解

丶Pz發表於2015-12-03

MJRefresh GitHub地址:https://github.com/CoderMJLee/MJRefresh

利用業餘時間研究了一下iOS的開發,發現OC特定的語法方式吸引了我,而且iOS開發中有很多有趣的東西,正是如此,重新激起了我對開發學習的興趣。自學過程中,知道了這個MJRefresh,MJ真乃大神也。

廢話不多說,MJRefresh整合了UIView,UICollectionView,UITableView的上下拉重新整理功能,而且還有自定義文字,動畫等功能。針對GitHub上的原始碼研究了一翻,打算照抄一遍,理解裡面的機制並且期待能從自己的實戰中學到新的東西。相信敲完一遍之後對它的理解又是一個新的層次。

MJRefresh的結構大致是這樣子的:

MJRefreshComponent自然是父類,它定義了基本的文字大小,顏色,重新整理事件,block,以及開始重新整理,結束重新整理等基本操作和屬性。

 1 @interface MJRefreshComponent : UIView
 2 {
 3     UIEdgeInsets _scrollViewOriginalInset;
 4     __weak UIScrollView *_scrollView;
 5 }
 6 
 7 #pragma mark - 文書處理
 8 /** 文字顏色 */
 9 @property (strong, nonatomic) UIColor *textColor;
10 /** 字型大小 */
11 @property (strong, nonatomic) UIFont *font;
12 
13 #pragma mark - 重新整理處理
14 /** 正在重新整理的回撥 */
15 @property (copy, nonatomic) void (^refreshingBlock)();
16 /** 設定回撥物件和回撥方法 */
17 - (void)setRefreshingTarget:(id)target refreshingAction:(SEL)action;
18 @property (weak, nonatomic) id refreshingTarget;
19 @property (assign, nonatomic) SEL refreshingAction;
20 /** 進入重新整理狀態 */
21 - (void)beginRefreshing;
22 /** 結束重新整理狀態 */
23 - (void)endRefreshing;
24 /** 是否正在重新整理 */
25 - (BOOL)isRefreshing;
26 @end

我個人認為,最重要的兩個類就是 MJRefreshHeader和MJRefreshFooter。因為重新整理事件的精髓就在這兩個類裡面,Footer不多做介紹。我個人理解是,主要通過KVO監聽 contentOffSet屬性變化來判斷當時是否是重新整理、還是下拉、還是正在重新整理或者改變重新整理狀態,核心程式碼當然我還是因為自身水平的原因沒太看懂,相信敲完一遍之後會明白吧。核心程式碼如下:

#pragma mark 根據contentOffset調整state
- (void)adjustStateWithContentOffset
{
    if (self.state != MJRefreshHeaderStateRefreshing) {
        // 在重新整理過程中,跳轉到下一個控制器時,contentInset可能會變
        _scrollViewOriginalInset = _scrollView.contentInset;
    }
    
    // 在重新整理的 refreshing 狀態,動態設定 content inset
    if (self.state == MJRefreshHeaderStateRefreshing ) {
        if(_scrollView.contentOffset.y >= -_scrollViewOriginalInset.top ) {
            _scrollView.mj_insetT = _scrollViewOriginalInset.top;
        } else {
            _scrollView.mj_insetT = MIN(_scrollViewOriginalInset.top + self.mj_h,
                                        _scrollViewOriginalInset.top - _scrollView.contentOffset.y);
        }
        return;
    }
    
    // 當前的contentOffset
    CGFloat offsetY = _scrollView.mj_offsetY;
    // 頭部控制元件剛好出現的offsetY
    CGFloat happenOffsetY = - _scrollViewOriginalInset.top;
    
    // 如果是向上滾動到看不見頭部控制元件,直接返回
    if (offsetY >= happenOffsetY) return;
    
    // 普通 和 即將重新整理 的臨界點
    CGFloat normal2pullingOffsetY = happenOffsetY - self.mj_h;
    if (_scrollView.isDragging) {
        self.pullingPercent = (happenOffsetY - offsetY) / self.mj_h;
        
        if (self.state == MJRefreshHeaderStateIdle && offsetY < normal2pullingOffsetY) {
            // 轉為即將重新整理狀態
            self.state = MJRefreshHeaderStatePulling;
        } else if (self.state == MJRefreshHeaderStatePulling && offsetY >= normal2pullingOffsetY) {
            // 轉為普通狀態
            self.state = MJRefreshHeaderStateIdle;
        }
    } else if (self.state == MJRefreshHeaderStatePulling) {// 即將重新整理 && 手鬆開
        self.pullingPercent = 1.0;
        // 開始重新整理
        self.state = MJRefreshHeaderStateRefreshing;
    } else {
        self.pullingPercent = (happenOffsetY - offsetY) / self.mj_h;
    }
}

最後呢,通過UIScrollView+MJRefresh擴充套件來實現UIScrollView的控制元件下拉重新整理整合。每多讀一次程式碼就有一次新的收穫。還等什麼,趕緊去敲出來吧。

相關文章