iOS-UITableView你需要掌握的屬性

weixin_34120274發表於2016-06-06

背景

  • 在現今的開發中,UITableView和UICollectionView算是最最流行的控制元件了,基本上每一個應用內部都會多次使用到這類控制元件,它們統一都繼承自UIScrollView
  • 平時我們都會用它們來展示資料,但是也有很多情況,比如頁面上下拖動的時候導航欄透明度改變、一個工具欄在頁面向上拖動到一定程度後懸浮到一個位置不動了、再比如簡書的個人頁面,頭像在導航欄上,頭像會隨著頁面的上下拖動變大變小、再比如上拉下拉重新整理的實現、再比如點選狀態列,tabbleView如果不是在最頂部,那麼它會立即滾動到頁面最頂部等等等等,這些效果全部都是通過UIScrollView的一些屬性實現的
  • 而且這類控制元件也算是我們開發中最基本的控制元件了,基本我們天天都需要和它們打交道,所以說,掌握它們的使用不僅僅是對我們最基本的要求,也可以讓我們實現很多效果,但是這些都需要建立在對它們一些易混淆屬性理解的基礎之上
  • 本文將以UITableView為例說明下它的一些關鍵屬性,並結合一些屬性簡單實現下拉重新整理
  • 先來看下這篇文章最後結合相關屬性講解的一個小Demo效果
313229-f151c96cfe1feb30.gif
refresh.gif

知識點

1)contenSize -- 滾動檢視內容的尺寸

  • 這個屬性是CGSize型別的,它決定了你的滾動檢視是否能滾動,能夠滾動多遠
  • 這個屬性對於實現我們本文要講解的下拉重新整理是至關重要的,我們需要明確contenSize包含了tabbleview的什麼內容,也就是什麼內容才算是contenSize的一部分
  • 除了UITableviewCell屬於contenSize的一部分之外,tabbleview的頭部和尾部檢視也算是它的contenSize的一部分
  • 如果設定了內邊距,那麼內邊距是不算contenSize的一部分的
  • 如果給tabbleview新增子控制元件,這個子控制元件也不屬於contenSize的一部分
  • 而且給scrollview內部子控制元件新增約束時,最頭疼的其實就是這個contenSize,它的contenSize需要根據子控制元件的尺寸以及子控制元件與scrollview之間的間距計算
313229-4dc7366bb227ca33.png
偏移量.png

2)contentOffset -- 偏移量

  • 是一個CGPoint型別的屬性,一般而言,上下滑動,我們需要它的contentOffset.y,左右滑動我們需要它的contentOffset.x
  • 這是一個滾動檢視最最基本的屬性,也是最重要的屬性,基本上,上述所有效果都是基於它來實現的
  • 當tabbleview是在一個導航條下面的話,那麼系統會自動將tabbleview內容增加64的頂部內邊距,因此它的偏移量y值預設是-64
  • 我們可以這樣去理解它,以一個上下滾動的tabbleview為例,contentOffset.y = tabbleview的frame的左上角的y值 - tabbleview的內容的左上角的y值,而且這個座標系以tabbleview的內容的左上角為座標原點
313229-0773c77b82c510bf.png
座標系.png

3)showsHorizontalScrollIndicatorshowsVerticalScrollIndicator

  • 是BOOL型別的,決定了是否隱藏水平或者垂直方法滾動條,之所以提及這2個屬性是要說一個注意點,比如我們在使用scrollview時,如果我們需要遍歷scrollview的子控制元件陣列,我們就需要注意這2個控制元件,它也算scrollview的子控制元件

4)scrollsToTop

  • 一個BOOL型別的屬性,可以控制點選狀態列,是否讓不在頂部的滾動檢視回到最頂部
  • 屬性預設為YES,也就是系統預設幫我們實現了這個效果
  • 需要說明的是如果頁面有2個及以上滾動檢視的時候,你需要控制哪一個滾動檢視支援scrollsToTop,哪些不支援

5)estimatedHeight --- 估算高度

  • 這裡針對tabbleview說一下這個屬性,因為tabbleview不需要我們自己計算contensize,所以預設情況下,tabbleview都是先呼叫heightForRow方法然後再去呼叫cellForRow方法,而且heightForRow會根據當前tabbleview有多少行就去呼叫多少次,無論是否cell當前被展示

  • 如果我們給了tabbleview一個估算高度,那麼它可以減少heightForRow方法的呼叫頻率,延遲計算目前不需要展示cell的高度,需要展示再去計算,這個也算是這個屬性的優點

  • 它也是有一定缺點的,既然是估算高度,那我們給多少算合適的,其實給多給少都不太好,給少了,它呼叫heightForRow方法就會多,給少了,雖然呼叫heightForRow方法少,但是tabbleview計算它的contensize的誤差就越大,明顯效果就是滾動條的高度很奇怪(跳躍性很大),所以還是根據cell平均值給一個估算高度

6)cellForRowAtIndexPath和indexPathForSelectedRow

  • cellForRowAtIndexPath這個方法根據傳入的indexPath可以獲得顯示在tableView上的某一行cell
  • indexPathForSelectedRow這個方法可以在系統沒有傳入indexPath的方法或者自定義的方法中,通過該方法獲得被選中的cell的indexPath,可以得到section,row,也是非常實用的

利用偏移量簡單實現一下下拉重新整理(仿新浪微博)

  • 其實一開始說的那些效果實現起來都是不難的,主要是我們需要對這些基本且關鍵屬性非常理解,知己知彼,百戰不殆嘛
  • 下面的這些程式碼主要是關於下拉過程中,更新下拉重新整理控制元件文字以及箭頭狀態的描述,關於傳送網路請求,這裡只是模擬一下傳送,新新增的資料也是假資料
  • 關於下拉重新整理控制元件是否作為tabbleview的頭部檢視,這個我是建議不要這樣做的,因為頭部檢視一般最好是用來作為輪播器或者廣告使用,我們一般最好把重新整理控制元件使用addSubview的方法新增到tabbleview上面最好
313229-c5b2d77462518c62.png
下拉重新整理.png
/**
 *  停止拖拽,需要在這個方法裡面監聽停止拖拽的時候偏移量,根據偏移量判斷重新整理控制元件是否完全顯示,是的話進入重新整理,不是的話直接返回
 */

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    // 如果正在重新整理, 直接返回
    if (self.isHeaderRefreshing) return;

    // 當偏移量 <= offsetY時(注意正負值), 重新整理控制元件就完全出現了
    CGFloat offsetY = - (self.tableView.contentInset.top + self.headerBtn.lb_height);
    [self.loadingView stopAnimating];
    self.headerBtn.imageView.hidden = NO;
    if (self.tableView.contentOffset.y <= offsetY) { // 重新整理header完全出現了
        // 進入重新整理狀態
        [self headerBeginRefresh];
    }
}
  • 還需要在scrollViewDidScroll方法中實時根據偏移量控制下拉重新整理控制元件文字以及箭頭的狀態,這個監控狀態的程式碼這裡不貼出來了,放在程式碼裡面有,註釋也是很詳細的
  • 開始重新整理方法實現
#pragma mark - 開始重新整理
- (void)headerBeginRefresh
{
    //如果當前正在重新整理,那麼不往下繼續執行
    if (self.isHeaderRefreshing) return;
    //否則,進入重新整理狀態
    self.headerRefreshing = YES;

    //顯示菊花
    self.loadingView.alpha = 1.0;
    [self.loadingView startAnimating];

    [self.headerBtn setTitle:@"載入中..." forState:UIControlStateNormal];

    self.headerBtn.imageView.transform = CGAffineTransformIdentity;
    self.headerBtn.imageView.hidden = YES;

    // 顯示載入中...,這個時候這個重新整理控制元件是會自己懸浮在導航欄下面,不需要人為拽著不鬆手
    //這個效果,我們可以通過增大tabbleview的內邊距來達到這個效果
    [UIView animateWithDuration:0.25f animations:^{

        //因為重新整理控制元件的y值就是-50,它自己高度也是50,所以只需要讓tabbleview內邊距向下走50,那麼重新整理控制元件就會完全顯示了
        UIEdgeInsets inset = self.tableView.contentInset;
        inset.top += self.headerBtn.lb_height;

        self.tableView.contentInset = inset;
    }];
    //由於是模擬傳送網路請求,所以延遲1.5秒後再去載入資料
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        // 傳送請求給伺服器
        [self loadNewData];
    });
}

  • 結束重新整理方法實現
#pragma mark - 結束重新整理
- (void)headerEndRefresh
{
    self.headerRefreshing = NO;
    self.headerBtn.hidden = YES;

    // 減小內邊距
    // 重新整理已經停止,不需要重新整理控制元件顯示在使用者能看到的範圍,所以需要減少tabbleview的內邊距
    [UIView animateWithDuration:0.25 animations:^{

        UIEdgeInsets inset = self.tableView.contentInset;
        inset.top -= self.headerBtn.lb_height;
        self.tableView.contentInset = inset;

    }completion:^(BOOL finished) {//重新整理控制元件縮回到使用者看不到的位置後,更新重新整理控制元件以及內部子控制元件的狀態
        self.headerBtn.hidden = NO;
        self.loadingView.alpha = 0.0;
        [self.loadingView stopAnimating];
    }];
}

ok,效果實現基本結束了,感謝您的閱讀,不足之處歡迎指正

點選檢視程式碼實現

相關文章