TL; DR: Высота, вычисленная механизмом автоотключения при отображении ячейки, содержащей просмотр коллекции, всегда ошибочна в первый раз. Вызов reloadData()
в представлении таблицы устраняет проблему, но также приводит к переходу таблицы и ее непригодности. Есть идеи?Использование автоматической компоновки в UITableViewCell, содержащей UICollectionView с нагрузкой асинхронного изображения
Пояснения: У меня есть табличный вид со множеством разных ячеек разной высоты.
Одна из этих ячеек - это галерея изображений, которая может содержать одно или несколько изображений, загружаемых асинхронно.
Ограничения У меня есть следующие:
- если галерея содержит только одно изображение, и если этот образ ориентирован в пейзаж, высота галереи должна быть высота изображения
- еще , галерея имеет фиксированную высоту.
Проблемы я сталкиваюсь являются следующими:
я получаю супер досадную Герметичную высоты-макет выпуска вещи, когда представление таблицы пытается отобразить в галерее клетки в первый раз. Эта инкапсулированная высота всегда имеет неправильное значение, даже если ограничение высоты в представлении коллекции обновлено.
Вид таблицы последовательно не получает размер ячейки сразу при первой попытке.
- Единственный способ, которым я могу получить, чтобы заставить вид таблицы, чтобы правильно отобразить ячейку, когда я называю reloadData на табличном после того, как изображение загружается в первый раз ... что делает табличный вид, чтобы прыгать и быть в основном непригодным для использования.
Я использую Kingfisher, чтобы получить изображения, вот код:
UICollectionViewCell Источник данных:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CarouselCollectionViewCell", forIndexPath: indexPath) as! CarouselCollectionViewCell
guard let collectionView = collectionView as? CarouselCollectionView else { return cell }
if let imagesURLs = data.imagesURLs {
let url = imagesURLs[indexPath.item]
if let smallURL = url.small {
KingfisherManager.sharedManager.retrieveImageWithURL(
smallURL,
optionsInfo: KingfisherOptionsInfo(),
progressBlock: nil,
completionHandler: { (image, error, cacheType, imageURL) ->() in
if let image = image {
self.delegate?.imageIsReadyForCellAtIndexPath(image, collectionView: collectionView, screenshotIndex: indexPath.row)
cell.imageView.image = image
}
})
}
}
return cell
}
Вот что происходит, когда делегат вызывается на RooViewController в imageIsReadyForCellAtIndexPath(image: UIImage, collectionView: UICollectionView, screenshotIndex: Int)
:
func imageIsReadyForCellAtIndexPath(image: UIImage, collectionView: UICollectionView, screenshotIndex: Int) {
guard let collectionView = collectionView as? CarouselCollectionView else { return }
guard let collectionViewIndexPath = collectionView.indexPath else { return }
guard let screenshotsCount = feed?.articles?[collectionViewIndexPath.section].content?[collectionViewIndexPath.row].data?.imagesURLs?.count else { return }
let key = self.cachedSizesIndexPath(collectionViewIndexPath: collectionViewIndexPath, cellIndexPath: NSIndexPath(forItem: screenshotIndex, inSection: 0))
var sizeToCache: CGSize!
if screenshotsCount == 1 {
// Resize the collectionView to fit a landscape image:
if image.isOrientedInLandscape {
sizeToCache = image.scaleToMaxWidthAndMaxHeight(maxWidth: Constants.maxImageWidth, maxHeight: Constants.maxImageHeight)
} else {
sizeToCache = image.scaleToHeight(Constants.maxImageHeight)
}
if collectionViewCellsCachedSizesObject.dict[key] == nil {
let flowLayout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
let imageWidth = sizeToCache.width
let sidesInset = (collectionView.frame.width - imageWidth)/2
print("sidesInset: ", sidesInset)
flowLayout.sectionInset = UIEdgeInsets(top: 0, left: sidesInset, bottom: 0, right: sidesInset)
collectionViewCellsCachedSizesObject.dict[key] = sizeToCache
collectionView.heightConstraint.constant = sizeToCache.height
collectionView.collectionViewLayout.invalidateLayout()
collectionView.setNeedsUpdateConstraints()
tableView.reloadData()
}
} else {
let sizeToCache = image.scaleToHeight(Constants.maxImageHeight)
if collectionViewCellsCachedSizesObject.dict[key] == nil { // && collectionViewCellsCachedSizesObject.dict[key] != sizeToCache {
collectionViewCellsCachedSizesObject.dict[key] = sizeToCache
collectionView.collectionViewLayout.invalidateLayout()
}
}
}
Вот как я могу установить Collection View:
class CarouselElement: Element {
let collectionView: CarouselCollectionView
func cachedSizesIndexPath(collectionViewIndexPath aCollectionViewIndexPath: NSIndexPath, cellIndexPath aCellIndexPath: NSIndexPath) -> String {
return "\(aCollectionViewIndexPath), \(aCellIndexPath)"
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
let layout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 0, left: Constants.horizontalPadding, bottom: 0, right: Constants.horizontalPadding)
layout.scrollDirection = .Horizontal
collectionView = CarouselCollectionView(frame: CGRectZero, collectionViewLayout: layout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.registerClass(CarouselCollectionViewCell.self, forCellWithReuseIdentifier: "CarouselCollectionViewCell")
collectionView.allowsMultipleSelection = false
collectionView.allowsSelection = true
collectionView.backgroundColor = Constants.backgroundColor
collectionView.showsHorizontalScrollIndicator = false
super.init(style: style, reuseIdentifier: reuseIdentifier)
addSubview(collectionView)
addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
"|[collectionView]|",
options: NSLayoutFormatOptions(),
metrics: nil,
views: ["collectionView":collectionView]))
addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
"V:|[collectionView]-verticalPadding-|",
options: NSLayoutFormatOptions(),
metrics: ["verticalPadding":Constants.verticalPadding],
views: ["collectionView":collectionView]))
collectionView.heightConstraint = NSLayoutConstraint(
item: collectionView,
attribute: .Height,
relatedBy: .Equal,
toItem: nil,
attribute: .NotAnAttribute,
multiplier: 1.0,
constant: 200)
addConstraint(collectionView.heightConstraint)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setCarouselDataSourceDelegate(dataSourceDelegate: CarouselDataSourceDelegate?, indexPath: NSIndexPath, cachedHeight: CGFloat?) {
collectionView.indexPath = indexPath
if let height = cachedHeight {
collectionView.heightConstraint.constant = height
}
collectionView.dataSource = dataSourceDelegate
collectionView.delegate = dataSourceDelegate
collectionView.reloadData()
}
override func prepareForReuse() {
super.prepareForReuse()
collectionView.contentOffset = CGPointZero
}}
И Пользовательские сотовый держа его:
class CarouselCollectionViewCell: UICollectionViewCell {
let imageView: UIImageView
override init(frame: CGRect) {
imageView = UIImageView.autolayoutView() as! UIImageView
imageView.image = Constants.placeholderImage
imageView.contentMode = .ScaleAspectFit
super.init(frame: frame)
translatesAutoresizingMaskIntoConstraints = false
addSubview(imageView)
addConstraints(
NSLayoutConstraint.constraintsWithVisualFormat(
"|[imageView]|",
options: NSLayoutFormatOptions(),
metrics: nil,
views: ["imageView":imageView]))
addConstraints(
NSLayoutConstraint.constraintsWithVisualFormat(
"V:|[imageView]|",
options: NSLayoutFormatOptions(),
metrics: nil,
views: ["imageView":imageView]))
}
override func prepareForReuse() {
imageView.image = Constants.placeholderImage
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
} }
И последнее, но не в последнюю очередь, я установил ограничение высоты вид сбора в tableView(_:willDisplayCell:forRowAtIndexPath:)
Я попытался установить его также в cellForRowAtIndexPath(_:)
, но это ничего не меняет.
Извините за массивный кусок кода, но это сводит меня с ума.
- значение «Encapsulated-Height-Layout» == rowheight в раскадровке? – Ismail
«Инкапсулированная высота-макет» равна 230, которая является стандартной высотой представления коллекции (200) + вертикальным интервалом (30) – Performat
Когда появится это предупреждение. скажите, что вам пришлось сломать одно из ваших ограничений, чтобы исправить это. Вероятно, (ограничение высоты), чтобы исправить это предупреждение, просто назначьте приоритет этого ограничения 999 (если он был 1000). – Ismail