Я работаю над набором классов, которые позволяют использовать UITableView
и связанные с ними классы для использования автоматического макета и динамического типа. Он основан на an answer on Stack Overflow, который направлен на добавление поддержки автоматического макета.Вычислить высоту экрана UITableViewCell с размерами классов
До сих пор он хорошо работает, но я столкнулся с несколькими проблемами при использовании классов размеров. Первая непосредственно связана с таблицей расчета высоты:
Когда я создаю новый UITableViewCell
, но не добавлять его в любые мнения, класс размера является Any
х Any
, поэтому, когда у меня есть несколько подвидов или ограничения, которые изменяются в зависимости от класса размера, они всегда работают так, как если бы они находились в ситуации Any
x Any
. До сих пор моя очень Hacky решение создать новый UIWindow
, что я добавляю клетки путем:
UIWindow(frame: UIScreen.mainScreen().applicationFrame)
Эта функция правильно, но у меня есть несколько вопросов с ним:
- Я сейчас создает весь новый
UIWindow
объект, который кажется неэффективным - Каждая ячейка должна быть добавлена в том же окне
- Когда экран вращается, класс размер может меняться (например, iPhone 6 Plus), так что мне нужно слушать изменения в кадре приложения и обновления кадра моего окна (пока не реализовано)
есть простой/более эффективный способ обеспечить 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 невозможно –