ios - source - uicollectionview swift 3 programmatically
El marco de la subvista es incorrecto al crear UICollectionViewCell (4)
Tuve el mismo problema con un UICollectionViewCell
usando restricciones de diseño automático.
Tuve que llamar a layoutIfNeeded
antes de configurar mi subvista que dependía del ancho del marco de las vistas.
El problema
Creé un UICollectionViewController con un UICollectionViewCell personalizado. La celda personalizada contiene una UIView grande y rectangular (llamada colorView) y una UILabel (llamada nameLabel).
Cuando la colección se llena por primera vez con sus celdas e imprimo colorView.frame, los marcos impresos tienen valores incorrectos. Sé que son incorrectos, porque los marcos colorView son más grandes que el marco de la celda, a pesar de que el colorView se dibuja correctamente.
Sin embargo, si desplazo la colecciónView lo suficiente para activar una reutilización de una celda creada anteriormente, el colorView.frame ahora tiene los valores correctos. Necesito los marcos correctos porque quiero aplicar esquinas redondeadas a la capa colorView y necesito el tamaño correcto de coloView para hacer esto. Por cierto, en caso de que se lo pregunte, colorView.bounds también tiene el mismo valor de tamaño incorrecto que el colorView.frame.
La pregunta
¿Por qué los marcos son incorrectos al crear las celdas?
Y ahora algo de código
Este es mi UICollectionViewCell:
class BugCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var colorView: UIView!
@IBOutlet weak var nameLabel: UILabel!
}
y este es el UICollectionViewController:
import UIKit
let reuseIdentifier = "Cell"
let colors = [UIColor.redColor(), UIColor.blueColor(),
UIColor.greenColor(), UIColor.purpleColor()]
let labels = ["red", "blue", "green", "purple"]
class BugCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return colors.count
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as BugCollectionViewCell
println("ColorView frame: /(cell.colorView.frame) Cell frame: /(cell.frame)")
cell.colorView.backgroundColor = colors[indexPath.row]
cell.nameLabel.text = labels[indexPath.row]
return cell
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let width = self.collectionView?.frame.width
let height = self.collectionView?.frame.height
return CGSizeMake(width!, height!/2)
}
}
La vista de colección está configurada para mostrar dos celdas a la vez, verticalmente, cada celda contiene un rectángulo grande pintado con un color y una etiqueta con el nombre del color.
Cuando acabo de ejecutar el código anterior en el simulador, obtengo el siguiente resultado impreso:
ColorView frame: (0.0,0.0,320.0,568.0) Cell frame: (0.0,0.0,375.0,333.5)
ColorView frame: (0.0,0.0,320.0,568.0) Cell frame: (0.0,343.5,375.0,333.5)
Es un resultado extraño: colorView.frame tiene una altura de 568 puntos, mientras que el cuadro de celda tiene solo 333.5 puntos de altura.
Si arrastro el collectionView hacia abajo y se vuelve a usar una celda, se imprime el siguiente resultado:
ColorView frame: (8.0,8.0,359.0,294.0) Cell frame: (0.0,1030.5,375.0,333.5)
ColorView frame: (8.0,8.0,359.0,294.0) Cell frame: (0.0,343.5,375.0,333.5)
Algo, que no puedo entender, sucedió en el camino que corrige el marco de colorView.
Creo que tiene algo que ver con el hecho de que la celda se carga desde el Nib, así que en lugar de usar el inicializador init (frame: frame), el controlador usa el inicializador init (coder: aCoder), por lo que tan pronto como la celda esté creado probablemente viene con un marco predeterminado que no puedo editar de todos modos.
Apreciaré cualquier ayuda que me permita entender lo que está sucediendo.
Estoy usando Xcode 6.1.1. con iOS SDK 8.1.
Ok, ahora entiendo que la celda se crea antes de que el diseño automático defina sus marcos. Esa es la razón por la cual en el momento de la creación los límites son incorrectos. Cuando las células se reutilizan, los marcos ya se han corregido.
Estaba teniendo este problema al crear una UIView personalizada que colocaba algunas capas y subvistas en coordenadas específicas. Cuando se crearon instancias de este UIView, la ubicación de las subvistas fue incorrecta (porque el diseño automático aún no se había iniciado).
Descubrí que en lugar de configurar las subvistas de la vista en init(coder: aCoder)
tuve que anular el método layoutSubviews()
. Esto se llama cuando el diseño automático solicita a cada vista que diseñe sus propias subvistas, por lo que en este punto, al menos, la vista padre tiene el marco correcto y puedo usarlo para colocar las subvistas correctamente.
Probablemente, si hubiera utilizado restricciones en el código de vista personalizada en lugar de ocuparme de los tamaños de fotogramas y el posicionamiento, entonces el diseño se habría realizado correctamente y no sería necesario anular el layoutSubviews()
las layoutSubviews()
.
Tuve este problema con el dibujo de Core Graphics en iOS 10, Swift 3.0.1 .
Aquí hay un método que me ayudó:
override func didMoveToSuperview() {
super.didMoveToSuperview()
setNeedsLayout()
layoutIfNeeded()
}
Mi problema fue que las formas de Core Graphics no se calcularon correctamente, porque no se llamó a un layoutSubviews()
.
Puede obtener los fotogramas finales de su celda anulando layoutIfNeeded () en su clase Cell personalizada de esta manera:
override func layoutIfNeeded() {
super.layoutIfNeeded()
self.subView.layer.cornerRadius = self.subView.bounds.width / 2
}
luego, en su método de origen de datos UICollectionView cellForRowAtIndexPath: haga esto:
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! CustomCollectionViewCell
cell.setNeedsLayout()
cell.layoutIfNeeded()