Ich habe UICollectionView (Flowlayout) verwendet, um ein einfaches Layout zu erstellen. Die Breite für jede Zelle wird mit auf die Bildschirmbreite eingestelltself.view.frame.width
Aber wenn ich das Gerät drehe, werden die Zellen nicht aktualisiert.
Ich habe eine Funktion gefunden, die bei Orientierungsänderung aufgerufen wird:
override func willRotateToInterfaceOrientation(toInterfaceOrientation:
UIInterfaceOrientation, duration: NSTimeInterval) {
//code
}
Ich kann jedoch keine Möglichkeit finden, das UICollectionView-Layout zu aktualisieren
Der Hauptcode ist hier:
class ViewController: UIViewController , UICollectionViewDelegate , UICollectionViewDataSource , UICollectionViewDelegateFlowLayout{
@IBOutlet weak var myCollection: UICollectionView!
var numOfItemsInSecOne: Int!
override func viewDidLoad() {
super.viewDidLoad()
numOfItemsInSecOne = 8
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
//print("orientation Changed")
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return numOfItemsInSecOne
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cellO", forIndexPath: indexPath)
return cell
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize{
let itemSize = CGSize(width: self.view.frame.width, height: 100)
return itemSize
}}
ios
swift
uicollectionview
flowlayout
Talha Ahmad Khan
quelle
quelle
collectionView
Eigenschaft, also rufen Sie sie einfach wie gesagt auf. Bearbeiten Sie sie einfach incollectionView.reloadData()
. Es wird klappen..invalidateLayout()
macht sehr viel Sinn.viewDidLayoutSubviews
Wenn meine App zum Porträt zurückkehrt, stürzt meine App ab, weil alte Layoutzellen zu groß sind.viewWillLayoutSubviews
funktioniert perfektDie bessere Option ist ein Anruf
invalidateLayout()
anstelle von,reloadData()
da dadurch die Wiederherstellung der Zellen nicht erzwungen wird, sodass die Leistung etwas besser ist:override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() myCollection.collectionViewLayout.invalidateLayout() }
quelle
viewWillLayoutSubviews
dann versuche es . Ich wette, Ihre Sammlungsansicht ist die Ansicht des View Controllers? Wenn ja, empfehle ich, es in eine andere Ansicht zu wickeln.UICollectionViewController
, da in diesem FallcollectionView
auch die Ansicht des Controllers angezeigt wird. Wenn Sie also dascollectionView
Layout ändern, werdenviewWillLayoutSubviews
verwandte Methoden aufgerufen.Sie können es auch auf diese Weise ungültig machen.
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; [self.collectionView.collectionViewLayout invalidateLayout]; }
quelle
Das viewWillLayoutSubviews () hat bei mir nicht funktioniert. ViewDidLayoutSubviews () auch nicht. Beide ließen die App in eine Endlosschleife gehen, die ich mit einem Druckbefehl überprüfte.
Eine der Möglichkeiten, die funktionieren, ist
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { // Reload here }
quelle
super.viewWillTransition...
Zum Aktualisieren
UICollectionViewLayout
kann auch dietraitCollectionDidChange
Methode verwendet werden:override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) guard previousTraitCollection != nil else { return } collectionView?.collectionViewLayout.invalidateLayout() }
quelle
Wenn
UICollectionLayout
eine Änderung der Grenzen festgestellt wird, werden Sie gefragt, ob das ungültige Layout umgeleitet werden muss. Sie können die Methode direkt umschreiben.UICollectionLayout
kann dieinvalidateLayout
Methode zum richtigen Zeitpunkt aufrufenclass CollectionViewFlowLayout: UICollectionViewFlowLayout{ /// The default implementation of this method returns false. /// Subclasses can override it and return an appropriate value /// based on whether changes in the bounds of the collection /// view require changes to the layout of cells and supplementary views. /// If the bounds of the collection view change and this method returns true, /// the collection view invalidates the layout by calling the invalidateLayout(with:) method. override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { return (self.collectionView?.bounds ?? newBounds) == newBounds } }
quelle
Sie können Ihr UICollectionView-Layout mithilfe von aktualisieren
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { if isLandscape { return CGSizeMake(yourLandscapeWidth, yourLandscapeHeight) } else { return CGSizeMake(yourNonLandscapeWidth, yourNonLandscapeHeight) } }
quelle
Anrufen
viewWillLayoutSubviews
ist nicht optimal. Versuchen Sie zuerst, dieinvalidateLayout()
Methode aufzurufen .Wenn der
The behaviour of the UICollectionViewFlowLayout is not defined
Fehler auftritt, müssen Sie überprüfen, ob alle Elemente in Ihrer Ansicht ihre Größe gemäß einem neuen Layout geändert haben. (Siehe die optionalen Schritte im Beispielcode.)Hier ist der Code, um Ihnen den Einstieg zu erleichtern. Abhängig von der Art und Weise, wie Ihre Benutzeroberfläche erstellt wird, müssen Sie möglicherweise experimentieren, um die richtige Ansicht zum Aufrufen der
recalculate
Methode zu finden. Dies sollte Sie jedoch zu Ihren ersten Schritten führen.override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) /// (Optional) Additional step 1. Depending on your layout, you may have to manually indicate that the content size of a visible cells has changed /// Use that step if you experience the `the behavior of the UICollectionViewFlowLayout is not defined` errors. collectionView.visibleCells.forEach { cell in guard let cell = cell as? CustomCell else { print("`viewWillTransition` failed. Wrong cell type") return } cell.recalculateFrame(newSize: size) } /// (Optional) Additional step 2. Recalculate layout if you've explicitly set the estimatedCellSize and you'll notice that layout changes aren't automatically visible after the #3 (collectionView.collectionViewLayout as? CustomLayout)?.recalculateLayout(size: size) /// Step 3 (or 1 if none of the above is applicable) coordinator.animate(alongsideTransition: { context in self.collectionView.collectionViewLayout.invalidateLayout() }) { _ in // code to execute when the transition's finished. } } /// Example implementations of the `recalculateFrame` and `recalculateLayout` methods: /// Within the `CustomCell` class: func recalculateFrame(newSize: CGSize) { self.frame = CGRect(x: self.bounds.origin.x, y: self.bounds.origin.y, width: newSize.width - 14.0, height: self.frame.size.height) } /// Within the `CustomLayout` class: func recalculateLayout(size: CGSize? = nil) { estimatedItemSize = CGSize(width: size.width - 14.0, height: 100) } /// IMPORTANT: Within the `CustomLayout` class. override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { guard let collectionView = collectionView else { return super.shouldInvalidateLayout(forBoundsChange: newBounds) } if collectionView.bounds.width != newBounds.width || collectionView.bounds.height != newBounds.height { return true } else { return false } }
quelle
Für mich geht das. Und das ist Code in Objective-C:
- (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; [collectionView.collectionViewLayout invalidateLayout]; }
quelle
Bitte verstehe das
traitCollectionDidChange (previousTraitCollection :) wird beim Drehen nicht auf dem iPad aufgerufen, da die Größenklasse sowohl im Hoch- als auch im Querformat regelmäßig ist. Es gibt viewWillTransition (to: with :), die aufgerufen wird, wenn sich die Größe der Sammlungsansicht ändert.
Außerdem sollten Sie UIScreen.mainScreen (). Bounds nicht verwenden, wenn Ihre App Multitasking unterstützt, da sie möglicherweise nicht den gesamten Bildschirm einnimmt. Verwenden Sie dazu besser collectionView.frame.width.
quelle
Mein Code:
override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() self.collectionView.collectionViewLayout.invalidateLayout() }
Wird richtig funktionieren !!!
quelle
Ich hatte auch ein Problem, aber dann wurde es gelöst mit:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { collectionViewFlowLayoutSetup(with: view.bounds.size.width) collectionView?.collectionViewLayout.invalidateLayout() collectionViewFlowLayoutSetup(with: size.width) } fileprivate func collectionViewFlowLayoutSetup(with Width: CGFloat){ if let flowLayout = collectionViewLayout as? UICollectionViewFlowLayout { flowLayout.estimatedItemSize = CGSize(width: Width, height: 300) } }
quelle
Ich löse dieses Problem, indem ich eine Benachrichtigung einstelle, wenn sich die Bildschirmausrichtung ändert, und eine Zelle neu lade, die die Elementgröße entsprechend der Bildschirmausrichtung festlegt und den Indexpfad auf die vorherige Zelle einstellt. Dies funktioniert auch mit Flowlayout. Hier ist der Code, den ich geschrieben habe:
var cellWidthInLandscape: CGFloat = 0 { didSet { self.collectionView.reloadData() } } var lastIndex: Int = 0 override func viewDidLoad() { super.viewDidLoad() collectionView.dataSource = self collectionView.delegate = self NotificationCenter.default.addObserver(self, selector: #selector(rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) cellWidthInLandscape = UIScreen.main.bounds.size.width } deinit { NotificationCenter.default.removeObserver(self) } @objc func rotated() { // Setting new width on screen orientation change cellWidthInLandscape = UIScreen.main.bounds.size.width // Setting collectionView to previous indexpath collectionView.scrollToItem(at: IndexPath(item: lastIndex, section: 0), at: .right, animated: false) } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { NotificationCenter.default.addObserver(self, selector: #selector(rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) } func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { // Getting last contentOffset to calculate last index of collectionViewCell lastIndex = Int(scrollView.contentOffset.x / collectionView.bounds.width) } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { // Setting new width of collectionView Cell return CGSize(width: cellWidthInLandscape, height: collectionView.bounds.size.height) }
quelle
Ich habe das Problem mit der folgenden Methode gelöst
override func viewDidLayoutSubviews() { if let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout { collectionView.collectionViewLayout.invalidateLayout() collectionView.collectionViewLayout = flowLayout } }
quelle