2014-01-07 192 views
76

我在過去的3或4個小時裏一直在用這種方式將我的頭撞在牆上,我似乎無法弄清楚。我有一個UIViewController裏面有一個全屏UITableView(屏幕上還有一些其他的東西,這就是爲什麼我不能使用UITableViewController),我想讓我的tableHeaderView通過自動佈局調整大小。不用說,這不合作。如何使用自動佈局設置tableHeaderView(UITableView)的高度?

查看下面的截圖。

enter image description here

因爲overviewLabel(例如,「在這裏列出的概述信息。」文)的動態內容,我使用的自動佈局調整它的大小和它的上海華。我已經調整好了所有的東西,除了tableHeaderView,它恰好位於hiearchy中的Paralax Table View之下。

我發現來調整該標題視圖的唯一方法是編程,用下面的代碼:

CGRect headerFrame = self.headerView.frame; 
headerFrame.size.height = headerFrameHeight; 
self.headerView.frame = headerFrame; 
[self.listTableView setTableHeaderView:self.headerView]; 

在這種情況下,headerFrameHeight是tableViewHeader高度的手工計算如下(innerHeaderView是白色區域,或第二「查看」,headerView是tableHeaderView)

CGFloat startingY = self.innerHeaderView.frame.origin.y + self.overviewLabel.frame.origin.y; 
CGRect overviewSize = [self.overviewLabel.text 
         boundingRectWithSize:CGSizeMake(290.f, CGFLOAT_MAX) 
         options:NSStringDrawingUsesLineFragmentOrigin 
         attributes:@{NSFontAttributeName: self.overviewLabel.font} 
         context:nil]; 
CGFloat overviewHeight = overviewSize.size.height; 
CGFloat overviewPadding = ([self.overviewLabel.text length] > 0) ? 10 : 0; // If there's no overviewText, eliminate the padding in the overall height. 
CGFloat headerFrameHeight = ceilf(startingY + overviewHeight + overviewPadding + 21.f + 10.f); 

手工計算工程,但如果事情在未來改變它的笨重且容易出錯。我希望能夠做的是讓tableHeaderView根據提供的約束條件自動調整大小,就像你可以在任何地方一樣。但對於我的生活,我無法弄清楚。

對此,有幾篇關於這方面的文章,但沒有一篇很清楚,最終讓我更困惑。這裏有幾個:

它並沒有真正做SENS e將translatesAutoresizingMaskIntoConstraints屬性更改爲NO,因爲這隻會對我造成錯誤,無論如何在概念上都沒有意義。

任何幫助真的很感謝!

編輯1: 感謝TomSwift的建議,我弄明白了。除了手動計算總覽的高度外,我可以按如下方式計算它,然後像以前那樣重新設置tableHeaderView。

[self.headerView setNeedsLayout]; 
[self.headerView layoutIfNeeded]; 
CGFloat height = [self.innerHeaderView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height + self.innerHeaderView.frame.origin.y; // adding the origin because innerHeaderView starts partway down headerView. 

CGRect headerFrame = self.headerView.frame; 
headerFrame.size.height = height; 
self.headerView.frame = headerFrame; 
[self.listTableView setTableHeaderView:self.headerView]; 

編輯2:正如其他人所指出的,張貼在編輯1解決方案似乎並不在viewDidLoad中工作。但是,它確實在viewWillLayoutSubviews中工作。下面的示例代碼:

// Note 1: The variable names below don't match the variables above - this is intended to be a simplified "final" answer. 
// Note 2: _headerView was previously assigned to tableViewHeader (in loadView in my case since I now do everything programatically). 
// Note 3: autoLayout code can be setup programatically in updateViewConstraints. 
- (void)viewWillLayoutSubviews { 
    [super viewWillLayoutSubviews]; 

    [_headerWrapper setNeedsLayout]; 
    [_headerWrapper layoutIfNeeded]; 
    CGFloat height = [_headerWrapper systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; 

    CGRect headerFrame = _headerWrapper.frame; 
    headerFrame.size.height = height; 
    _headerWrapper.frame = headerFrame; 
    _tableView.tableHeaderView = _headerWrapper; 
} 
+1

'setTableHeaderView'在Xcode6上不起作用。問題是單元格被tableHeaderView重疊。但是,它在Xcode5上工作 –

+0

@DawnSong知道Xcode6的解決方案,以便我可以更新答案? –

+1

經過大量試用後,我使用UITableViewCell而不是tableHeaderView,它可以工作。 –

回答

33

您需要使用UIView systemLayoutSizeFittingSize:方法來獲得您的標題視圖的最小邊界大小。

我提供這個Q/A使用此API進一步討論:

How to resize superview to fit all subviews with autolayout?

+0

它的高度= 0回來,雖然我不是100%確定我配置它正確,因爲這不是一個UITableViewCell,所以沒有contentView調用「systemLayoutSizeFittingSize」。我試過的: [self.headerView setNeedsLayout]; [self.headerView layoutIfNeeded]; CGFloat height = [self.headerView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize] .height; CGRect headerFrame = self.headerView.frame; headerFrame.size.height = height; self.headerView.frame = headerFrame; [self.listTableView setTableHeaderView:self.headerView]; 我也確認preferredMax ...是有效的。 –

+0

啊哈!想通了,我需要做[self.innerHeaderView systemLayoutSizeFittingSize ...]而不是self.headerView,因爲這是什麼有實際的動態內容。萬分感謝! –

3

你使用systemLayoutSizeFittingSize解決方案:如果工作頭視圖只是每個視圖的外觀更新一次。在我的情況下,標題視圖多次更新以反映狀態更改。但systemLayoutSizeFittingSize:始終報告相同的大小。也就是說,大小對應於第一次更新。

要獲得systemLayoutSizeFittingSize:每次更新我有更新它之前先刪除表頭視圖後返回正確的尺寸重新添加它:

self.listTableView.tableHeaderView = nil; 
[self.headerView removeFromSuperview]; 
20

我真的有這個作戰和plonking的安裝到viewDidLoad沒有爲我工作,因爲框架沒有在viewDidLoad中設置,我也結束了大量凌亂的警告,封裝的頭自動佈局高度被減少到0.我只注意到iPad上的問題時在表單呈現中呈現tableView。

什麼解決了我的問題是在viewWillLayoutSubviews而不是viewDidLoad中設置tableViewHeader。

func viewWillLayoutSubviews() { 
     super.viewWillLayoutSubviews() 
     if tableView.tableViewHeaderView == nil { 
      let header: MyHeaderView = MyHeaderView.createHeaderView() 
      header.setNeedsUpdateConstraints() 
      header.updateConstraintsIfNeeded() 
      header.frame = CGRectMake(0, 0, CGRectGetWidth(tableView.bounds), CGFloat.max) 
      var newFrame = header.frame 
      header.setNeedsLayout() 
      header.layoutIfNeeded() 
      let newSize = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize) 
      newFrame.size.height = newSize.height 
      header.frame = newFrame 
      self.tableView.tableHeaderView = header 
     } 
    } 
+0

這真的很棒! – Vishnuvardhan

+0

終於爲我工作的解決方案!謝謝 – konradowy

11

我發現了一種優雅的方式來使用自動佈局調整表頭,有和沒有動畫。

只需將其添加到您的視圖控制器。

func sizeHeaderToFit(tableView: UITableView) { 
    if let headerView = tableView.tableHeaderView { 
     let height = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height 
     var frame = headerView.frame 
     frame.size.height = height 
     headerView.frame = frame 
     tableView.tableHeaderView = headerView 
     headerView.setNeedsLayout() 
     headerView.layoutIfNeeded() 
    } 
} 

要根據動態變化的標籤調整:

@IBOutlet weak var makeThisTallerHeight: NSLayoutConstraint! 

@IBAction func makeThisTaller(sender: AnyObject) { 

    UIView.animateWithDuration(0.3) { 
     self.tableView.beginUpdates() 
     self.makeThisTallerHeight.constant += 20 
     self.sizeHeaderToFit(self.tableView) 
     self.tableView.endUpdates() 
    } 
} 

見AutoResizingHeader項目,看到這個:

@IBAction func addMoreText(sender: AnyObject) { 
    self.label.text = self.label.text! + "\nThis header can dynamically resize according to its contents." 
} 

override func viewDidLayoutSubviews() { 
    // viewDidLayoutSubviews is called when labels change. 
    super.viewDidLayoutSubviews() 
    sizeHeaderToFit(tableView) 
} 

要根據約束的改變動畫調整大小行動。 https://github.com/p-sun/Swift2-iOS9-UI

AutoResizingHeader

+0

嘿太陽。謝謝你的好例子。似乎我有問題tableViewHeader。我試圖在你的例子中有相同的約束,但不工作。我應該如何添加約束來標記我想要增加高度?感謝您的任何建議 – Bonnke

+1

請確保您將要更高級別的標籤綁定到'@IBOutlet makeThisTaller'和'@IBAction fun makeThisTaller'上(如示例中所示)。此外,將標籤的所有邊限制在tableViewHeader(例如頂部,底部,左側和右側)。 –

+0

非常感謝!最後通過添加下面這行來解決: 'lblFeedDescription.preferredMaxLayoutWidth = lblFeedDescription.bounds.width' 其中label是我想要增加大小的那個。謝謝 ! – Bonnke

1

這個工作對我的ios10和Xcode的8

func layoutTableHeaderView() { 

    guard let headerView = tableView.tableHeaderView else { return } 
    headerView.translatesAutoresizingMaskIntoConstraints = false 

    let headerWidth = headerView.bounds.size.width; 
    let temporaryWidthConstraints = NSLayoutConstraint.constraintsWithVisualFormat("[headerView(width)]", options: NSLayoutFormatOptions(rawValue: UInt(0)), metrics: ["width": headerWidth], views: ["headerView": headerView]) 

    headerView.addConstraints(temporaryWidthConstraints) 

    headerView.setNeedsLayout() 
    headerView.layoutIfNeeded() 

    let headerSize = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize) 
    let height = headerSize.height 
    var frame = headerView.frame 

    frame.size.height = height 
    headerView.frame = frame 

    self.tableView.tableHeaderView = headerView 

    headerView.removeConstraints(temporaryWidthConstraints) 
    headerView.translatesAutoresizingMaskIntoConstraints = true 

} 
0

在我的情況viewDidLayoutSubviews更好地工作。 viewWillLayoutSubviews會導致出現tableView的白線。此外,我補充檢查我的headerView對象是否已經存在。

- (void)viewDidLayoutSubviews 
{ 
    [super viewDidLayoutSubviews]; 

    if (! self.userHeaderView) { 
     // Setup HeaderView 
     self.userHeaderView = [[[NSBundle mainBundle] loadNibNamed:@"SSUserHeaderView" owner:self options:nil] objectAtIndex:0]; 
     [self.userHeaderView setNeedsLayout]; 
     [self.userHeaderView layoutIfNeeded]; 
     CGFloat height = [self.userHeaderView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; 
     CGRect headerFrame = self.userHeaderView.frame; 
     headerFrame.size.height = height; 
     self.userHeaderView.frame = headerFrame; 
     self.tableView.tableHeaderView = self.userHeaderView; 

     // Update HeaderView with data 
     [self.userHeaderView updateWithProfileData]; 
    } 
} 
0

該解決方案的大小調整和tableHeaderView避免在viewDidLayoutSubviews()方法我用一些其他的答案在這裏有無限循環:

override func viewDidLayoutSubviews() { 
    super.viewDidLayoutSubviews() 

    if let headerView = tableView.tableHeaderView { 
     let height = headerView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height 
     var headerFrame = headerView.frame 

     // comparison necessary to avoid infinite loop 
     if height != headerFrame.size.height { 
      headerFrame.size.height = height 
      headerView.frame = headerFrame 
      tableView.tableHeaderView = headerView 
     } 
    } 
} 

參見這篇文章:https://stackoverflow.com/a/34689293/1245231

相關問題