我一直在處理一組允許UITableView
及其相關類使用自動佈局和動態類型的類。它基於an answer on Stack Overflow,旨在添加自動佈局支持。使用大小分類計算UITableViewCell offscreen的高度
到目前爲止,它運行良好,但使用尺寸類時遇到了一些問題。首先是直接關係到表計算的高度:
當我創建一個新的UITableViewCell
,但不要把它添加到任何意見,大小類是Any
X Any
,所以當我有一些子視圖或根據尺寸等級改變的約束條件,他們總是工作,就好像他們在Any
x Any
的情況。到目前爲止,我非常哈克解決方案是創建一個新的UIWindow
,我由單元添加到:
UIWindow(frame: UIScreen.mainScreen().applicationFrame)
此功能正常,但我有幾個問題吧:
- 我現在正在打造一個全新的
UIWindow
對象,這似乎效率不高 - 每個細胞都有被添加到同一窗口
- 當屏幕旋轉時,尺寸規格可能會改變(即iPhone 6個加),所以我需要監聽更改應用程序框架和更新我的窗口的框架(尚未實現)
是否有保證UITableViewCell
知道它的大小類容易/更有效的方式,而不必創建新的UIWindow
,還是更有效地做到這一點?也許我可以添加一個
目前大部分代碼都可以通過GitHub page被發現,但最相關的方法是:
DynamicTableViewController
private var cachedClassesForCellReuseIdentifiers = [String : UITableViewCell.Type]()
private var cachedNibsForCellReuseIdentifiers = [String : UINib]()
private var offscreenCellRowsForReuseIdentifiers = [String : UITableViewCell]()
private var offScreenWindow: UIWindow = {
return UIWindow(frame: UIScreen.mainScreen().applicationFrame)
}()
override public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
// This method is called with an NSMutableIndexPath, which is not compatible with an imutable NSIndexPath,
// so we create an imutable NSIndexPath to be passed to the following methods
let imutableIndexPath = NSIndexPath(forRow: indexPath.row, inSection: indexPath.section)
if let reuseIdentifier = self.cellReuseIdentifierForIndexPath(imutableIndexPath) {
if let cell = self.cellForReuseIdentifier(reuseIdentifier) {
self.configureCell(cell, forIndexPath: indexPath)
if let dynamicCell = cell as? DynamicTableViewCell {
let height = dynamicCell.heightInTableView(tableView)
return height
} else {
// Fallback for non-DynamicTableViewCell cells
let size = cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
let cellBoundsHeight = CGRectGetHeight(cell.bounds)
if size.height > 0 && size.height >= cellBoundsHeight {
// +1 for the cell separator
return size.height + 1
} else {
// In some situations (such as the content view not having any/enough constraints to get a height), the
// size from the systemLayoutSizeFittingSize: will be 0. However, because this can _sometimes_ be intended
// (e.g., when adding to a default style; see: DynamicSubtitleTableViewCell), we just return
// the height of the cell as-is. This may make some cells look wrong, but overall will also prevent 0 being returned,
// hopefully stopping some things from breaking.
return cellBoundsHeight + 1
}
}
}
}
return UITableViewAutomaticDimension
}
private func cellForReuseIdentifier(reuseIdentifier: String) -> UITableViewCell? {
if self.offscreenCellRowsForReuseIdentifiers[reuseIdentifier] == nil {
if let cellClass = self.cachedClassesForCellReuseIdentifiers[reuseIdentifier] {
let cell = cellClass()
self.offScreenWindow.addSubview(cell)
self.offscreenCellRowsForReuseIdentifiers[reuseIdentifier] = cell
} else if let cellNib = self.cachedNibsForCellReuseIdentifiers[reuseIdentifier] {
if let cell = cellNib.instantiateWithOwner(nil, options: nil).first as? UITableViewCell {
self.offScreenWindow.addSubview(cell)
self.offscreenCellRowsForReuseIdentifiers[reuseIdentifier] = cell
}
}
}
return self.offscreenCellRowsForReuseIdentifiers[reuseIdentifier]
}
DynamicTableViewCell
public func heightInTableView(tableView: UITableView) -> CGFloat {
var height: CGFloat!
if self.calculateHeight {
self.setNeedsUpdateConstraints()
self.updateConstraintsIfNeeded()
self.bounds = CGRectMake(0, 0, CGRectGetWidth(tableView.bounds), CGRectGetHeight(self.bounds))
self.setNeedsLayout()
self.layoutIfNeeded()
let size = self.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
let boundsHeight = CGRectGetHeight(self.bounds)
if size.height > 0 && size.height >= boundsHeight {
// +1 for the cell separator
height = size.height + 1
} else {
// In some situations (such as the content view not having any/enough constraints to get a height), the
// size from the systemLayoutSizeFittingSize: will be 0. However, because this can _sometimes_ be intended
// (e.g., when adding to a default style; see: DynamicSubtitleTableViewCell), we just return
// the height of the cell as-is. This may make some cells look wrong, but overall will also prevent 0 being returned,
// hopefully stopping some things from breaking.
height = boundsHeight + 1
}
} else {
height = self.cellHeight
}
if height < self.minimumHeight && self.minimumHeight != nil {
return self.minimumHeight!
} else {
return height
}
}
該解決方案適用於iOS 7和8,以及任何未來的解決方案。這個限制也消除了UITraitCollection
的使用,所以我還沒有沿着這條路線走下去(我甚至不確定它會有幫助)
我實現曾經使用的iOS 8的自動高度計算對於單元格,但我有幾個問題,我也需要這個與iOS 7一起工作,所以使用和iOS 8 only解決方案是不可能的 –