Swift: How to refresh UICollectionView layout after rotation of the device

后端 未结 14 916
闹比i
闹比i 2020-12-01 02:38

I used UICollectionView (flowlayout) to build a simple layout. the width for each cell is set to the width of screen using self.view.frame.width

but whe

14条回答
  •  猫巷女王i
    2020-12-01 03:00

    Calling viewWillLayoutSubviews is not optimal. Try calling the invalidateLayout() method first.

    If you experience the The behaviour of the UICollectionViewFlowLayout is not defined error, you need to verify if all the elements within your view's have changed its sizes, according to a new layout. (see the optional steps within the example code)

    Here is the code, to get you started. Depending on the way your UI is created, you may have to experiment to find the right view to call the recalculate method, yet that should guide you towards your first steps.

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

提交回复
热议问题