iOS 預估值estimatedHeight實現headerView和cell自適應高度佈局機制踩坑

iOS estimate預設高度自適應

  • 前提緩存

在iOS開發中tableView的cell自適應高度是常見的需求,以前採起過masonry約束佈局cell內部計算最終高度進行高度緩存返回的方式,這樣的優勢比較高效,可是計算高度代碼相對複雜。在沒有追求極致計算效率的前提下,昨天嘗試了下系統提供的estimate設置預估值高度後系統會根據約束自動計算高度。函數

  • 問題佈局

首先扯一點同事關於佈局約束的使用的問題,自定義cell .m文件中重寫initWithStyle方法進行了cell上控件建立和添加。可是約束寫在了layoutSubviews方法裏。這樣在一般狀況下是沒有問題的,可是昨天我在此代碼基礎上去用預估值高度進行cell自適應高度時,發現了約束錯亂的結果,而且沒有高度自動計算。因而寫個demo找緣由,控制器中預設高度自適應核心代碼self.tableView.estimatedRowHeight = 100;self.tableView.rowHeight = UITableViewAutomaticDimension;
自定義cell .m代碼和效果以下:
圖片描述
圖片描述spa

若是把layoutSubviews中的佈局約束寫在 initWihStyle函數中 addSubviews以後就是正常:
圖片描述
圖片描述3d

另外cell自定義xib進行拖線Autolayout約束也是正常的,只要約束是正確的:垂直方向約束從上到下必定要飽滿 top bottom 都知足,那麼系統去根據約束計算的時候就不會差。不然基本都是約束條件不知足形成的混亂。代理

  • 機制猜測對象

爲何layoutSubView中去進行約束影響了系統去計算高度呢?進行了代碼追蹤後猜測的結果是estimate是在全部垂直條件都知足的狀況下才能計算出高度,不然用預設高度。而且計算高度的時機是要快於layoutSunview方法的觸發的,也就是說在layoutSubview去寫約束的話會致使約束滯後,系統計算超前。並且用layoutSubViews方法時須要注意時機:每次label進行賦值的時候或者tableView滑動的時候都會觸發layoutSubViews方法。blog

  • 系統自動計算內容圖片

另系統提供了estimatedRowHeight(cell高度預估值)、estimatedSectionHeaderHeight(headerView預估值)、estimatedSectionFooterHeight(footerView預估值)三個部位均可以讓系統自動計算高度。開發

  • 遇坑例子

重點來了,系統自動計算高度在cell中是計算contentView裏控件的約束高度好比在headerView或者footerView中用imageView設置背景圖的時候,若是全部的控件都是經過self.contentView addSubview的方式進行添加的話,那麼背景圖imageView不要添加在self.contentView上,由於背景圖都是上下左右約束好的或者frame = self.frame。這樣就知足了預設定高度的系統計算條件,會拿imageView的高度做爲計算計算結果,因此下面動態高度的控件也就不會自適應了。那麼就想一個辦法,不讓系統計算高度去計算imageView的高度,讓系統計算別的控件的佈局高度:
圖片描述

沒錯,這麼寫imageView會覆蓋全部控件,因此[self insertSubview:_backGrooundImageView belowSubview:self.contentView];把iamgeView壓到了self.contentView下面,這樣的話既不會覆蓋也不會被系統計算高度。結果就是contentView上面全部的控件高度約束計算出來後,返回這個高度,而且背景圖imageView不受影響。

圖片描述
圖片描述

  • 總結

一、用頭視圖來總結:在頭視圖建立以前,系統用預設高度做爲heightForHeader的高度進行繪製,在控件都加載出來以後而且約束肯定以後計算出控件約束的真實高度再次返回(heghtForHeader代理方法會走兩次)。
二、系統自動計算高度的時機是在cententView內容繪製成功後。準確計算出高度的充分條件是控件垂直方向約束要「完美」。注意有top和bottom的約束是否知足,不然會混亂。
三、系統計算高度的對象是contentView層上的控件。

  • 感謝

時間比較倉促簡單記錄一下工做中碰見的問題和本身的一點點看法, 若是有不足之處或者錯誤理解的地方歡迎各位道友指出謝謝~

相關文章
相關標籤/搜索