Aggiornato per Swift 5
preferredLayoutAttributesFittingAttributes
rinominato in preferredLayoutAttributesFitting
e usa il dimensionamento automatico
Aggiornato per Swift 4
systemLayoutSizeFittingSize
rinominato in systemLayoutSizeFitting
Aggiornato per iOS 9
Dopo aver visto la mia soluzione GitHub rompere sotto iOS 9, ho finalmente avuto il tempo di indagare a fondo sul problema. Ora ho aggiornato il repository per includere diversi esempi di diverse configurazioni per celle con dimensionamento automatico. La mia conclusione è che le cellule auto dimensionanti sono grandi in teoria ma disordinate in pratica. Un avvertimento quando si procede con le celle di dimensionamento automatico.
TL; DR
Dai un'occhiata al mio progetto GitHub
Le celle con ridimensionamento automatico sono supportate solo con il layout del flusso, quindi assicurati che sia quello che stai utilizzando.
Ci sono due cose che devi configurare per far funzionare le celle con ridimensionamento automatico.
1. Impostare estimatedItemSize
suUICollectionViewFlowLayout
Il layout del flusso diventerà di natura dinamica una volta impostata la estimatedItemSize
proprietà.
self.flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
2. Aggiungi il supporto per il dimensionamento nella sottoclasse della tua cella
Questo è disponibile in 2 gusti; Layout automatico o sostituzione personalizzata di preferredLayoutAttributesFittingAttributes
.
Crea e configura celle con Auto Layout
Non entrerò nei dettagli di questo in quanto esiste un brillante post SO sulla configurazione dei vincoli per una cella. Diffida solo che Xcode 6 abbia rotto un sacco di cose con iOS 7, quindi, se supporti iOS 7, dovrai fare cose come assicurarti che la maschera di ridimensionamento automatico sia impostata sul contenuto della cella e che i limiti del contenuto siano impostati come limiti della cella quando la cella è caricata (esawakeFromNib
).
Le cose di cui devi essere consapevole è che la tua cella deve essere più seriamente vincolata di una cella vista tabella. Ad esempio, se vuoi che la tua larghezza sia dinamica, la tua cella ha bisogno di un vincolo di altezza. Allo stesso modo, se si desidera che l'altezza sia dinamica, sarà necessario un vincolo di larghezza per la cella.
Implementa preferredLayoutAttributesFittingAttributes
nella tua cella personalizzata
Quando questa funzione viene chiamata, la vista è già stata configurata con il contenuto (ovvero cellForItem
è stata chiamata). Supponendo che i tuoi vincoli siano stati impostati in modo appropriato, potresti avere un'implementazione come questa:
//forces the system to do one layout pass
var isHeightCalculated: Bool = false
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
//Exhibit A - We need to cache our calculation to prevent a crash.
if !isHeightCalculated {
setNeedsLayout()
layoutIfNeeded()
let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
var newFrame = layoutAttributes.frame
newFrame.size.width = CGFloat(ceilf(Float(size.width)))
layoutAttributes.frame = newFrame
isHeightCalculated = true
}
return layoutAttributes
}
NOTA Su iOS 9 il comportamento è leggermente cambiato e potrebbe causare arresti anomali della tua implementazione se non stai attento (vedi di più qui ). Quando si implementapreferredLayoutAttributesFittingAttributes
è necessario assicurarsi di modificare il frame degli attributi di layout una sola volta. In caso contrario, il layout chiamerà l'implementazione indefinitamente e alla fine si arresterà in modo anomalo. Una soluzione è memorizzare nella cache la dimensione calcolata nella cella e invalidarla ogni volta che riutilizzi la cella o ne cambi il contenuto come ho fatto con ilisHeightCalculated
proprietà.
Prova il tuo layout
A questo punto dovresti avere celle dinamiche "funzionanti" nella tua raccolta. Non ho ancora trovato la soluzione pronta all'uso sufficiente durante i miei test, quindi sentiti libero di commentare se hai. Sembra ancoraUITableView
vincere la battaglia per il dimensionamento dinamico dell'IMHO.
Avvertenze
Ricorda che se stai utilizzando celle prototipo per calcolare la stimata Dimensione oggetto, ciò si interromperà se XIB utilizza classi di dimensioni . La ragione di ciò è che quando carichi la tua cella da una XIB verrà configurata la sua classe di dimensioni Undefined
. Questo verrà interrotto solo su iOS 8 e versioni successive poiché su iOS 7 la classe di dimensioni verrà caricata in base al dispositivo (iPad = Regular-Any, iPhone = Compact-Any). È possibile impostare stimaItemSize senza caricare XIB oppure caricare la cella da XIB, aggiungerla a collectionView (questo imposterà traitCollection), eseguire il layout e rimuoverlo dalla superview. In alternativa, puoi anche fare in modo che la tua cella prevalga sul traitCollection
getter e restituisca i tratti appropriati. Tocca a voi.
Fammi sapere se ho perso qualcosa, spero di aver aiutato e buona fortuna con la programmazione