2011-03-14 26 views
4

問題 - 怎樣才能最好的計算高度的行中一個UITableViewController的「heightForRowAtIndexPath」的方法,因爲:當單元格甚至沒有構建時,我如何計算heightForRowAtIndexPath?

  1. 我使用的是子類的UITableViewCell &子視圖的實際尺寸定製(如UILabels)在運行時計算&依賴於諸如用戶是否更改字體大小等事情
  2. 單元格實際上並沒有準備好它似乎在「heightForRowAtIndexPath」之前,因此您不能依靠調用您的特定自定義單元格即時查詢

我現在唯一能想到的事情是: 1.在您的自定義UITableViewCell子類中,創建一個計算每個子視圖高度的方法(例如, UILabel),它位於UITableViewCell子類中 - 然後在創建實例時在單元子類中使用它。 2.同樣在自定義子類中,創建一個運行所有UILabel的類方法,調用上述方法,總結高度並因此計算出總行高度。它必須得到傳遞給它的數據(例如每個UILabels中的文本) 3.在UITableViewController「heightForRowAtIndexPath」中,您必須調用上面(2)中的「calRowHeight」類型方法,將標籤文本數據。因此,有效地調用您的定製單元格子類中的類方法,該類方法知道如何計算出總行高度,但它使用的是與單元格相同的邏輯...

是否有比這更簡單的方法我失蹤?

+0

我已經在我的自定義的UITableViewCell子引入一個類的方法做到了這一點,正如你所提到的。它有效,但我也質疑效率。 – chris 2011-03-14 06:15:09

回答

14

當創建一個UITableView並且每當你發送一個reloadData消息時,數據源就會爲每個單元發送一個heightForRowAtIndexPath消息。所以如果你的表格有30個單元格,那麼這個消息會被髮送30次。

說這30個單元格中只有6個在屏幕上可見。在這種情況下,當創建併發送reloadData消息時,UITableView將在每個可見行發送一個cellForRowAtIndexPath消息,即該消息被髮送六次。

蘋果爲什麼像這樣實施它?其中一部分原因是,計算行高度比構建和填充整個單元格要便宜得多。鑑於在許多表格中,每個單元格的高度都是相同的,它通常要便宜得多。部分原因是因爲iOS需要知道整個表的大小:這允許它創建滾動條並將其設置在滾動視圖中等。

如果您的行高因尺寸不同而不同可以使用不同數量的文本,您可以使用相關字符串上的sizeWithFont:方法之一來進行計算。這比構建視圖然後測量結果更快。請注意,如果您更改單元格的高度,則需要重新加載整個表格(使用reloadData - 這將詢問代表每個高度,但只詢問可見單元格),或者選擇性地重新加載大小已滿的行改變。

其他材料 如果我理解在評論跟進的問題,以下可能會有幫助:

如果要實現編輯模式,那麼它的情況並不少見需要改變你的表的高度行。例如,您的表格行中可能有文本,並且它們的單元格變得更窄時 - 爲右側的刪除圓圈留出空間 - 您可能希望某些單元格變得更高以容納文本。這裏的基本方法是:

  • 確保tableView:heightForRowAtIndexPath:方法知道您是否處於編輯模式。 (它可以使用isEditing來詢問tableView。)然後讓方法返回正確的高度,這取決於你是否處於編輯模式。

  • 在UITableViewController中的setEditing:animated方法(或者UIViewController,無論你使用什麼 - 取決於你使用什麼,都有一些差異,所以值得仔細檢查文檔)發送reloadData消息到tableView之後你已經改變了它的狀態。這將強制tableView抓住每一行的高度,並將重新獲取可見行的單元格。當您進入編輯模式時,tableView處理使單元變窄,但如果您想在佈局上做更多工作,請在tableView:cellForRowAtIndex:中執行。如上所述,總體策略是找到一種快速計算高度的方法。隨着文字sizeWithFont:(及其變體)可以做到這一點。如果你有圖片等,那麼你可以抓住他們的尺寸並做一些總和。

  • 除了這些步驟之外,您可能還想在切換模式後滾動tableView。如果行的高度不同,那麼切換模式後,表格中的位置將會錯誤。我在這裏採用的一種方法是在重新加載表格以調用執行滾動調整的方法之後,使用performSelector:withObject:afterDelay。您需要使用延遲,以便讓tableView有時間收集新的高度和新的表格單元格。 (這可能是一個更明智的方法。)我根據tableView:cellForRowAtIndexPath:在重載之前和之後屏幕上單元格第一個可見行的origin.y之間的差異做了一些調整以進行滾動調整。所以,例如,爲了在預加載之前得到位置,有點像這樣。

    CGPoint offset = [[self tableView] contentOffset]; 
    NSIndexPath* indexPath = [[self tableView] indexPathForRowAtPoint:CGPointMake(0,offset.y)]; 
    CGFloat preCellOffset = [[[self tableView] cellForRowAtIndexPath:indexPath] origin].y; 
    
+0

謝謝 - 重新您的最後一句話,爲情景tableview進出編輯模式,我假設我會使用「layoutViews」方法 - 我還沒有試圖看看有沒有辦法從這個方法來設置自定義tableviewcell的行高? – Greg 2011-03-14 09:01:41

+0

感謝您的優秀更新 - 有趣的是,我採取了LavaSlider的建議,並在heightForRowAtIndexPath我(一)使用cellForRowAtIndexPath生成一個臨時單元格,然後(b)調用layoutSubviews,使子視圖設置。然後,我要採取由此產生的單元格視圖大小,但這似乎並不奏效:(我提出了一個問題,在這個http://stackoverflow.com/questions/5304301/does-a-uitableviewcell-contentview-frame-size - 增加 - 自動添加後 – Greg 2011-03-14 23:08:07

+0

我推薦的方法是你在另一個問題中描述爲「手動查看所有子視圖(例如UILabels)並手動確定整體高度是多少」。知道你的單元格有多複雜,但根據我的經驗,手動計算是相當簡單的,它絕對是最高效的(更快,佔用更少的內存) - 無論如何,獲得工作解決方案的好運氣我已經找到了自由日誌在tableView委託/數據源方法幫助我瞭解什麼時候被調用,什麼取決於什麼等等。 – Obliquely 2011-03-14 23:44:09

3

我過去所做的事情,我不確定是最有效的,是從我的heightForRowAtIndexPath方法調用cellForRowAtIndexPath,然後我問視圖的單元格的高度。我爲頁眉和頁腳高度做了類似的事情。這樣,如果我更改單元格,頁眉或頁腳,我不必記得去更新相應的高度方法。

+0

多數民衆贊成在有趣的 - 將有趣的聽到,如果任何人支持這一點,或可以證實它不是一個有效的方法。我試圖記住,如果heightForRowAtIndexPath被調用的只是有限數量的將要顯示的單元格而不是所有單元格? (希望它會是前者) – Greg 2011-03-14 03:50:41

+0

它只能在屏幕上顯示或部分顯示單元格。在'cellForRowAtIndexPath'和'heightForRowAtIndexPath'中放置一個NSLog(),它報告行和部分,然後在它們被調用時觀察。 – LavaSlider 2011-03-14 03:58:28

+0

是否會延遲將此標記爲答案,直到我檢查由cellForRowAtIndexPath生成的合成臨時單元是否可以很容易地用於獲取整體高度。請參閱問題我在這裏http://stackoverflow.com/questions/5304301/does-a-uitableviewcell-contentview-frame-size-increase-automatically-after-adding – Greg 2011-03-14 23:09:37

相關問題