uicollectionviewflowlayoutautomaticsize uicollectionviewdelegateflowlayout collection automatic ios swift autolayout uicollectionview

ios - automatic - uicollectionviewdelegateflowlayout



UICollectionView cambio de tamaƱo de las celdas cuando se eliminan elementos con estimatedItemSize (1)

Tengo un proyecto simple con un guión gráfico que contiene solo un UICollectionViewController , construido con Xcode 7.1.1 para iOS 9.1

class ViewController: UICollectionViewController { var values = ["tortile", "jetty", "tisane", "glaucia", "formic", "agile", "eider", "rooter", "nowhence", "hydrus", "outdo", "godsend", "tinkler", "lipscomb", "hamlet", "unbreeched", "fischer", "beastings", "bravely", "bosky", "ridgefield", "sunfast", "karol", "loudmouth", "liam", "zunyite", "kneepad", "ashburn", "lowness", "wencher", "bedwards", "guaira", "afeared", "hermon", "dormered", "uhde", "rusher", "allyou", "potluck", "campshed", "reeda", "bayonne", "preclose", "luncheon", "untombed", "northern", "gjukung", "bratticed", "zeugma", "raker"] @IBOutlet weak var flowLayout: UICollectionViewFlowLayout! override func viewDidLoad() { super.viewDidLoad() flowLayout.estimatedItemSize = CGSize(width: 10, height: 10) } override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return values.count } override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCellWithReuseIdentifier("MyCell", forIndexPath: indexPath) as! MyCell cell.name = values[indexPath.row] return cell } override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { values.removeAtIndex(indexPath.row) collectionView.deleteItemsAtIndexPaths([indexPath]) } } class MyCell: UICollectionViewCell { @IBOutlet weak var label: UILabel! var name: String? { didSet { label.text = name } } }

Al eliminar las celdas de la vista de colección, todas las celdas restantes se animan a su estimatedItemSize , y luego vuelven a cambiar al tamaño correcto.

Curiosamente, esto produce advertencias de restricción de diseño automático para cada celda cuando se produce la animación:

2015-12-02 14:30:45.236 CollectionTest[1631:427853] Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don''t want. Try this: (1) look at each constraint and try to figure out which you don''t expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you''re seeing NSAutoresizingMaskLayoutConstraints that you don''t understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) ( "<NSAutoresizingMaskLayoutConstraint:0x14556f780 h=--& v=--& H:[UIView:0x1456ac6c0(10)]>", "<NSLayoutConstraint:0x1456acfd0 UIView:0x1456ac6c0.trailingMargin == UILabel:0x1456ac830''raker''.trailing>", "<NSLayoutConstraint:0x1456ad020 UILabel:0x1456ac830''raker''.leading == UIView:0x1456ac6c0.leadingMargin>" ) Will attempt to recover by breaking constraint <NSLayoutConstraint:0x1456acfd0 UIView:0x1456ac6c0.trailingMargin == UILabel:0x1456ac830''raker''.trailing>

Mi primer pensamiento fue que romper estas restricciones era lo que estaba causando el problema de cambio de tamaño.

Actualizando el método awakeFromNib la célula:

override func awakeFromNib() { super.awakeFromNib() contentView.translatesAutoresizingMaskIntoConstraints = false }

corrige las advertencias, pero el problema aún ocurre.

Traté de volver a agregar mis propias restricciones entre la celda y su contentView , pero esto no resolvió el problema:

override func awakeFromNib() { super.awakeFromNib() contentView.translatesAutoresizingMaskIntoConstraints = false for constraint in [ contentView.leadingAnchor.constraintEqualToAnchor(leadingAnchor), contentView.trailingAnchor.constraintEqualToAnchor(trailingAnchor), contentView.topAnchor.constraintEqualToAnchor(topAnchor), contentView.bottomAnchor.constraintEqualToAnchor(bottomAnchor)] { constraint.priority = 999 constraint.active = true } }

¿Pensamientos?


el diseño de flujo calcula los tamaños reales de las celdas después de hacer el diseño por tamaños estimados para definir cuáles son visibles. Después de eso, ajusta el diseño según los tamaños reales.

Sin embargo, cuando se anima, cuando calcula la posición inicial para la animación, no llega a la etapa de eliminación de las células y ejecuta el diseño automático allí, por lo que solo utiliza tamaños estimados.

La forma más fácil es tratar de dar los tamaños estimados más cercanos, o si puede proporcionar el tamaño en el delegado en la llamada sizeForItemAt .

En mi caso, estaba intentando animar los atributos de diseño sin insertar o eliminar celdas y, para ese caso específico, UICollectionViewFlowLayout y luego UICollectionViewFlowLayout este método:

override func invalidateLayout(with context: UICollectionViewLayoutInvalidationContext) { if !context.invalidateEverything && context.invalidatedItemIndexPaths == nil && context.contentOffsetAdjustment == .zero && context.contentSizeAdjustment == .zero { return } super.invalidateLayout(with: context) }

Esto evita recalcular atributos de diseño usando tamaños estimados cuando no se ha cambiado nada.