2014-09-22 60 views
77

我有一個UITableView,其中使用自動佈局在故事板中定義了自定義UITableViewCell。該單元有幾個多行UILabelsUITableView動態單元格高度僅在滾動後纔會更正

UITableView似乎可以正確計算單元格高度,但對於前幾個單元格,高度在標籤之間沒有正確劃分。 滾動一下後,一切都按預期工作(即使最初不正確的單元格)。

- (void)viewDidLoad { 
    [super viewDidLoad] 
    // ... 
    self.tableView.rowHeight = UITableViewAutomaticDimension; 
} 


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    TableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"TestCell"]; 
    // ... 
    // Set label.text for variable length string. 
    return cell; 
} 

有什麼我可能會丟失,這是導致汽車佈局不能夠在前幾次完成其工作?

我創建了一個演示此行爲的sample project

Sample project: Top of table view from sample project on first load. Sample project: Same cells after scrolling down and back up.

+0

我也面臨這個問題,但下面的答案是不是爲我工作,在此 – 2016-06-28 12:07:55

+0

任何幫助面臨着同樣的問題,增加layoutIfNeeded細胞不起作用我呢?更多的建議 – Max 2016-09-05 13:01:53

回答

96

我不知道這是明確記載或沒有,但加入[cell layoutIfNeeded]纔回到小區解決您的問題。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    TableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"TestCell"]; 
    NSUInteger n1 = firstLabelWordCount[indexPath.row]; 
    NSUInteger n2 = secondLabelWordCount[indexPath.row]; 
    [cell setNumberOfWordsForFirstLabel:n1 secondLabel:n2]; 

    [cell layoutIfNeeded]; // <- added 

    return cell; 
} 
+2

我很想知道,爲什麼只有第一次通過纔有必要?如果我將調用放在單元的'-awakeFromNib'中的'-layoutIfNeeded',它也可以工作。我寧願只調用'layoutIfNeeded',我知道爲什麼它是必要的。 – blackp 2014-09-23 00:33:40

+2

爲我工作!我很想知道爲什麼它是必需的! – Mustafa 2015-01-16 11:22:55

+0

如果你渲染尺寸類,不同於任何X – 2015-05-07 21:49:45

0
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ 


// call the method dynamiclabelHeightForText 
} 

使用哪個動態返回高度該行的上述方法。 並將相同的動態高度分配給您使用的標籤。

-(int)dynamiclabelHeightForText:(NSString *)text :(int)width :(UIFont *)font 
{ 

    CGSize maximumLabelSize = CGSizeMake(width,2500); 

    CGSize expectedLabelSize = [text sizeWithFont:font 
           constrainedToSize:maximumLabelSize 
            lineBreakMode:NSLineBreakByWordWrapping]; 


    return expectedLabelSize.height; 


} 

此代碼可幫助您找到標籤中文本顯示的動態高度。

+0

實際上是Ramesh,只要設置了tableView.estimatedRowHeight和tableView.rowHeight = UITableViewAutomaticDimension屬性,就不需要這樣做。另外,確保自定義單元格對各種小部件和contentView有適當的限制。 – BonanzaDriver 2015-01-15 22:39:42

4

在我的情況下,第一次顯示單元格時,UILabel的最後一行被截斷。它發生得非常隨機,正確調整大小的唯一方法是將單元格從視圖中滾動並將其恢復。 我嘗試了迄今爲止顯示的所有可能的解決方案(layoutIfNeeded..reloadData),但沒有爲我工作。訣竅是將「Autoshrink」設置爲Minimuum Font Scale(對我而言爲0.5)。試一試

+0

這適用於我,而不應用上面列出的任何其他解決方案。很棒的發現。 – mckeejm 2015-09-09 20:49:52

+0

但是這autoshrinks文本...爲什麼要在表視圖中有不同大小的文字?看起來很糟糕。 – 2017-09-29 14:43:10

18

cellForRowAtIndexPath中添加[cell layoutIfNeeded]對於最初滾動到視野範圍內的單元格不起作用。

也沒有用[cell setNeedsLayout]預處理它。

您仍然需要將某些單元格向外滾動並返回到視圖中才能正確調整大小。

這很令人沮喪,因爲大多數開發人員都具有動態類型,自動佈局和自定義大小的單元格可以正常工作 - 除了這個煩人的情況。這個bug會影響我所有「更高」的表格視圖控制器。

+0

同樣適用於我。當我第一次滾動時,單元格的大小是44px。如果我滾動以使細胞看不到並回來,它的大小適當。你有沒有找到解決方案? – Max 2015-06-18 13:56:15

+3

取消選中「使用大小班級」爲我們工作! – 2015-08-03 10:54:06

+0

謝謝@ ashy_32bit這也爲我解決了它。 – ImpurestClub 2015-08-18 17:52:19

2

我嘗試了此頁面中的所有解決方案,但取消選中使用大小類,然後再次檢查解決了我的問題。

編輯:取消選中尺寸類會導致故事板上出現很多問題,所以我嘗試了另一種解決方案。我在視圖控制器的ViewDidLoadViewWillAppear方法中填充tableView。這解決了我的問題。

9

我在我的一個項目中也有同樣的經歷。

爲什麼會發生?

在Storyboard中爲某些設備設計了一些寬度的單元。例如400px。例如,您的標籤具有相同的寬度。從故事板加載時,它的寬度爲400px。

這裏有一個問題:

tableView:heightForRowAtIndexPath:單元佈局之前調用它的子視圖。

因此它計算寬度爲400px的標籤和單元格的高度。但是你在屏幕上運行設備,例如320px。這個自動計算的高度不正確。僅僅因爲電池的layoutSubviews僅在tableView:heightForRowAtIndexPath: 之後發生即使您在layoutSubviews中手動爲您的標籤設置preferredMaxLayoutWidth也沒有幫助。

我的解決辦法:

1)子類UITableView並重寫dequeueReusableCellWithIdentifier:forIndexPath:。設置單元格寬度等於表格寬度和強制單元格的佈局。

- (UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath { 
    UITableViewCell *cell = [super dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath]; 
    CGRect cellFrame = cell.frame; 
    cellFrame.size.width = self.frame.size.width; 
    cell.frame = cellFrame; 
    [cell layoutIfNeeded]; 
    return cell; 
} 

2)子類UITableViewCell。 在layoutSubviews中爲您的標籤手動設置preferredMaxLayoutWidth。您還需要手動佈局contentView,因爲它沒有細胞框架的變化後,自動佈局(我不知道爲什麼,但它是)

- (void)layoutSubviews { 
    [super layoutSubviews]; 
    [self.contentView layoutIfNeeded]; 
    self.yourLongTextLabel.preferredMaxLayoutWidth = self.yourLongTextLabel.width; 
} 
+1

當我遇到了這個問題,我也需要確保實現代碼如下的框架是正確的,所以我叫[self.tableview layoutIfNeeded]被填充的tableview之前(在viewDidLoad中)。 – GK100 2016-05-30 18:34:31

1

我有一個調整的標籤,所以我的東東只是做的問題
chatTextLabel.text = chatMessage.message chatTextLabel?.updateConstraints()後設置文本

//完整的代碼

func setContent() { 
    chatTextLabel.text = chatMessage.message 
    chatTextLabel?.updateConstraints() 

    let labelTextWidth = (chatTextLabel?.intrinsicContentSize().width) ?? 0 
    let labelTextHeight = chatTextLabel?.intrinsicContentSize().height 

    guard labelTextWidth < originWidth && labelTextHeight <= singleLineRowheight else { 
     trailingConstraint?.constant = trailingConstant 
     return 
    } 
    trailingConstraint?.constant = trailingConstant + (originWidth - labelTextWidth) 

    } 
3

添加約束所有conten表視圖自定義單元格內噸,然後估計表視圖行的高度,並設置行HIGHT到自動尺寸與在viewdid負載:

override func viewDidLoad() { 
    super.viewDidLoad() 

    tableView.estimatedRowHeight = 70 
    tableView.rowHeight = UITableViewAutomaticDimension 
} 

爲了解決這個問題初始加載問題在自定義表視圖細胞申請layoutIfNeeded方法與:

class CustomTableViewCell: UITableViewCell { 

override func awakeFromNib() { 
    super.awakeFromNib() 
    self.layoutIfNeeded() 
    // Initialization code 
} 
} 
+0

不爲我工作 – 2017-09-29 14:38:45

+0

設置'estimatedRowHeight'爲值> 0是很重要的,而不是'UITableViewAutomaticDimension'(這是-1),否則自動行高度將無法正常工作。 – 2017-11-13 10:07:46

0

在我的情況,與細胞高度問題發生在初始表視圖被加載後,與一個用戶動作發生(攻絲上的按鈕,在具有改變的細胞的效果的細胞高度)。我一直無法得到的細胞改變其高度,除非我做的:

[self.tableView reloadData]; 

我曾嘗試

[cell layoutIfNeeded]; 

,但沒有奏效。

13

這爲我工作,當其他類似的解決方案都沒有:

override func didMoveToSuperview() { 
    super.didMoveToSuperview() 
    layoutIfNeeded() 
} 

這似乎是一個實際的錯誤,因爲我非常熟悉的自動版式,以及如何使用UITableViewAutomaticDimension,但是我還是偶爾會遇到這個問題。我很高興終於找到了解決問題的辦法。

+1

比接受的答案更好,因爲只有在從xib而不是每個單元格顯示加載單元格時纔會調用它。更少的代碼行。 – 2017-03-23 05:22:43

+2

這是一個真正的寶石。謝謝。 – 2017-04-09 22:25:28

+1

不要忘記調用'super.didMoveToSuperview()' – cicerocamargo 2017-09-28 11:36:36

6

我有類似的問題,在第一次加載時,行高不計算,但在一些滾動或轉到另一個屏幕後,我回到這個屏幕行計算。在第一次加載時,我的物品從互聯網加載,在第二次加載時,我的物品首先從Core Data加載,然後從互聯網上重新加載,我注意到行高從互聯網重新加載時計算。所以我注意到,當在segue動畫中調用tableView.reloadData()(與push和present segue相同的問題)時,行高不計算。所以我隱藏tableview在視圖初始化,並把一個活動加載程序,以防止對用戶醜陋的影響,我在300毫秒後調用tableView.reloadData現在問題得到解決。我認爲這是一個UIKit錯誤,但是這個解決方法可以解決這個問題。

我把論文線(雨燕3.0)在我的項目負荷完成處理

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300), execute: { 
     self.tableView.isHidden = false 
     self.loader.stopAnimating() 
     self.tableView.reloadData() 
    }) 

這解釋了爲什麼有些人,把reloadData在layoutSubviews解決問題

+0

這是唯一一個爲我工作的華盛頓州。除非我不使用isHidden,但在添加數據源時將表的alpha設置爲0,然後在重新加載後將其設置爲1。 – 2017-11-13 10:05:46

0

在斯威夫特3.我有每次更新可重用單元的文本時調用self.layoutIfNeeded()。

import UIKit 
import SnapKit 

class CommentTableViewCell: UITableViewCell { 

    static let reuseIdentifier = "CommentTableViewCell" 

    var comment: Comment! { 
     didSet { 
      textLbl.attributedText = comment.attributedTextToDisplay() 
      self.layoutIfNeeded() //This is a fix to make propper automatic dimentions (height). 
     } 
    } 

    internal var textLbl = UILabel() 

    override func layoutSubviews() { 
     super.layoutSubviews() 

     if textLbl.superview == nil { 
      textLbl.numberOfLines = 0 
      textLbl.lineBreakMode = .byWordWrapping 
      self.contentView.addSubview(textLbl) 
      textLbl.snp.makeConstraints({ (make) in 
       make.left.equalTo(contentView.snp.left).inset(10) 
       make.right.equalTo(contentView.snp.right).inset(10) 
       make.top.equalTo(contentView.snp.top).inset(10) 
       make.bottom.equalTo(contentView.snp.bottom).inset(10) 
      }) 
     } 
    } 
} 

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
     let comment = comments[indexPath.row] 
     let cell = tableView.dequeueReusableCell(withIdentifier: CommentTableViewCell.reuseIdentifier, for: indexPath) as! CommentTableViewCell 
     cell.selectionStyle = .none 
     cell.comment = comment 
     return cell 
    } 

commentsTableView.rowHeight = UITableViewAutomaticDimension 
    commentsTableView.estimatedRowHeight = 140 
2

Attatching screenshot for your referance對我來說,這些方法都沒有工作,但我發現標籤有在Interface Builder明確Preferred Width集。刪除(取消選中「顯式」),然後使用UITableViewAutomaticDimension按預期工作。

+0

只有這一個工作 – SARATH 2017-10-03 13:13:14

0

在我的情況下,我正在更新其他週期。因此,在設置labelText後,tableViewCell高度已更新。我刪除了異步塊。

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    let cell = tableView.dequeueReusableCell(withIdentifier:Identifier, for: indexPath) 
    // Check your cycle if update cycle is same or not 
    // DispatchQueue.main.async { 
     cell.label.text = nil 
    // } 
} 
0

上述解決方案都無法正常工作,但以下方法的組合都做了。

只好在viewDidLoad()中添加以下內容。

DispatchQueue.main.async { 

     self.tableView.reloadData() 

     self.tableView.setNeedsLayout() 
     self.tableView.layoutIfNeeded() 

     self.tableView.reloadData() 

    } 

reloadData,setNeedsLayout和layoutIfNeeded的上述組合工作,但沒有任何其他。可能是特定於項目中的單元格。是的,必須調用reloadData兩次以使其工作。

而且設置的viewDidLoad以下

tableView.rowHeight = UITableViewAutomaticDimension 
tableView.estimatedRowHeight = MyEstimatedHeight 

在的tableView(_的tableView:UITableView的,cellForRowAt indexPath:IndexPath)

cell.setNeedsLayout() 
cell.layoutIfNeeded() 
0

只要確保你不是在「設置標籤文本willdisplaycell'表視圖的委託方法。 在'cellForRowAtindexPath'委託方法中設置標籤文本以進行動態高度計算。

你是歡迎:)

0

在我的情況下,在電池堆疊視圖是造成問題。這顯然是一個錯誤。一旦我將其刪除,問題就解決了。

3

我已經嘗試了這個問題的大部分答案,並沒有得到任何他們的工作。我發現的唯一的功能性的解決辦法是將以下內容添加到我的UITableViewController子類:

override func viewWillAppear(_ animated: Bool) { 
    super.viewWillAppear(animated) 
    UIView.performWithoutAnimation { 
     tableView.beginUpdates() 
     tableView.endUpdates() 
    } 
} 

是必需的UIView.performWithoutAnimation通話,否則你會看到正常的表視圖動畫作爲視圖控制器負載。

+0

工作,肯定比調用reloadData兩次 – 2017-07-19 12:33:10

+0

這是唯一的解決方案,爲我工作以及 Swift 3,Xcode 8.3.3 – 2017-08-01 21:41:22

+0

黑魔法。在'viewWillAppear'中做它不適合我,但在'viewDidAppear'中做。 – Martin 2017-10-11 14:45:21

0

我遇到了這個問題,並通過將我的視圖/標籤初始化代碼從tableView(willDisplay cell:)移動到tableView(cellForRowAt:)來修復它。

+0

這是不*推薦的方式來初始化單元格。 'willDisplay'將比'cellForRowAt'具有更好的性能。使用最新版本來實現正確的單元格。 – Martin 2017-10-11 14:41:46

0

問題是,我們有一個有效的行高之前,初始單元格加載。 解決方法是在視圖出現時強制重新加載表。

- (void)viewDidAppear:(BOOL)animated 
{ 
    [super viewDidAppear:animated]; 
    [self.tableView reloadData]; 
} 
相關問題