Swift: comment rafraîchir la disposition de UICollectionView après la rotation de l'appareil

J'ai utilisé UICollectionView (flowlayout) pour construire une mise en page simple. la largeur de chaque cellule est définie à la largeur de l'écran en utilisant self.view.frame.width

mais quand je tourne l'appareil, les cellules ne sont pas mises à jour.

enter image description here

j'ai trouvé une fonction, qui est appelée changement d'orientation :

override func willRotateToInterfaceOrientation(toInterfaceOrientation: 
  UIInterfaceOrientation, duration: NSTimeInterval) {
    //code
}

mais je suis incapable de trouver un moyen de mettre à jour le layout UICollectionView

Le code principal est ici:

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
    }}
28
demandé sur Ajaxharg 2016-04-27 11:30:25

8 réponses

Ajouter cette fonction:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews() 
    myCollection.collectionViewLayout.invalidateLayout()
}

Lorsque vous modifiez l'orientation, cette fonction sera appelée.

27
répondu Khuong 2017-11-05 15:33:41

La meilleure option est d'appeler invalidateLayout() au lieu de reloadData() parce que cela ne forcera pas la récréation des cellules, donc la performance sera légèrement meilleure:

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews() 
    myCollection.collectionViewLayout.invalidateLayout()
}
33
répondu kelin 2017-08-12 09:01:29

Vous pouvez également l'invalider de cette façon.

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

    [self.collectionView.collectionViewLayout invalidateLayout]; 
}
9
répondu awuu 2017-10-24 07:21:55

Le viewWillLayoutSubviews() ne fonctionne pas pour moi. Ni viewDidLayoutSubviews (). Les deux ont fait l'application aller dans une boucle infinie que j'ai vérifié en utilisant une commande d'impression.

l'Un des moyens qui ne travail est

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
// Reload here
}
5
répondu The Doctor 2018-01-09 20:12:32

Vous pouvez mettre à jour votre mise en page UICollectionView en utilisant

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    if isLandscape {
        return CGSizeMake(yourLandscapeWidth, yourLandscapeHeight)
    }
    else {
        return CGSizeMake(yourNonLandscapeWidth, yourNonLandscapeHeight)
    }
}
3
répondu Abhinandan Pratap 2016-04-27 08:57:07

pour mettre à jour UICollectionViewLayout

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)

    guard let previousTraitCollection = previousTraitCollections else {
        return
    }
    collectionView?.collectionViewLayout.invalidateLayout()
}
3
répondu birdy 2017-12-06 15:18:23

j'ai été aussi avoir un problème, mais cela a résolu en utilisant :

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)
        }

    }
0
répondu user2698544 2018-09-11 18:00:33

Je résous cela en définissant la notification quand l'orientation de l'écran change et en rechargeant la cellule qui définit itemsize en fonction de l'orientation de l'écran et en définissant indexpath à la cellule précédente. Cela fonctionne aussi avec flowlayout. Voici le code que j'ai écrit:

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)

}
0
répondu Yubraj Basyal 2018-10-04 03:41:27