简体   繁体   中英

UICollectionViewCell resizing on device rotation

I have a very simple UICollectionView embedded in a ViewController.

The UICollectionView uses auto-layout (defined in IB) to take the whole space in the ViewController.

My UICollectionViewCell have all the same size and they take the whole space of the UICollectionView because I want only one cell to be displayed in the ViewController. The UICollectionViewCell displays only an UIImage (which is embedded in a UIScrollView for zooming).

It works fine except when the device rotate. There's an error message:

The behavior of the UICollectionViewFlowLayout is not defined because: the item height must be less than the height of the UICollectionView minus the section insets top and bottom values, minus the content insets top and bottom values. The relevant UICollectionViewFlowLayout instance is , and it is attached to ; animations = { bounds.origin=; bounds.size=; position=; }; layer = ; contentOffset: {0, 0}; contentSize: {4875, 323}> collection view layout: .

That's pretty clear, I need to resize my UICollectionViewCell to fit the new height / width. After the rotation the UICollectionViewCell display with the appropriate height / width but with a poor animation.

Here's the code:

@IBOutlet weak var theCollectionView: UICollectionView!
@IBOutlet weak var theFlowLayout: UICollectionViewFlowLayout!
    override func viewDidLoad() {
    super.viewDidLoad()

    //theCollectionView.delegate = self
    theCollectionView.dataSource = self
    automaticallyAdjustsScrollViewInsets = false
    theFlowLayout.itemSize = theCollectionView.frame.size
    theFlowLayout.sectionInset = UIEdgeInsetsMake(0,0,0,0)
    theFlowLayout.minimumLineSpacing = 0.0
    theCollectionView.reloadData()
}


override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
}

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    print("\(#function) \(view.frame.size)")
    coordinator.animate(alongsideTransition: nil, completion: {
        _ in
        self.theFlowLayout.itemSize = self.theCollectionView.frame.size
    })        
}

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    print("\(#function) \(view.frame.size)")
}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    print("\(#function) \(view.frame.size)")
}

The question is, how and when perform the UICollectionViewCell change to avoid the warning and get the smooth animation?

When the device rotation happens, I can see the following: viewWillTransition(to:with:) (375.0, 667.0) viewWillLayoutSubviews() (667.0, 375.0) viewDidLayoutSubviews() (667.0, 375.0)

The error is displayed just after the viewDidLayoutSubviews(). I have tried to call theFlowLayout.invalidateLayout() in viewDidLayoutSubviews() but it doesn't change the issue.

I have read others similar questions but I could not find my answer :-(

Thanks for your help,

Sebastien

I have not found the best solution but at least it works.

I use viewWillTransition to compute the index of the cell and to reset the offset after the rotation. To avoid poor animation I set the alpha to 0 and at the beginning and to 1 again at the end of the animation.

viewWillLayoutSubviews is used to invalidated the layout of the UICollectionViewFlowLayout and viewDidLayoutSubviews to set the new cell size.

Maybe it will help others but if you have a better solution, please share it!

    @IBOutlet weak var theCollectionView: UICollectionView! {
    didSet {
        theCollectionView.backgroundColor = UIColor.black
        theCollectionView.delegate = self
        theCollectionView.dataSource = self
    }
}

@IBOutlet weak var theFlowLayout: UICollectionViewFlowLayout! {
    didSet {
        theFlowLayout.itemSize = theCollectionView.frame.size
        theFlowLayout.sectionInset = UIEdgeInsetsMake(0,0,0,0)
        theFlowLayout.minimumLineSpacing = 0.0
    }
}

var assets:[PHAsset]!
var startAssetIndex = 0

override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = UIColor.black
    automaticallyAdjustsScrollViewInsets = false
    theCollectionView.reloadData()
}


override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    theCollectionView.scrollToItem(at: IndexPath(row:startAssetIndex, section:0), at: .left, animated: true)
}


/// Resize the collectionView during device rotation
///
/// - Parameters:
///   - size: New size of the viewController
///   - coordinator: coordinator for the animation
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    // Compute the index of the image/video currently displayed
    let offset = self.theCollectionView.contentOffset;
    let index = round(offset.x / self.theCollectionView.bounds.size.width);

    // hide the collection view to avoid horrible animation during the rotation
    // animation is horrible due to the offset change
    theCollectionView.alpha = 0.0
    coordinator.animate(alongsideTransition: nil, completion: {
        _ in
        // display the collectionView during the animation
        self.theCollectionView.alpha = 1.0

        // compute the new offset based on the index and the new size
        let newOffset = CGPoint(x: index * self.theCollectionView.frame.size.width, y: offset.y)
        self.theCollectionView.setContentOffset(newOffset, animated: false)
    })
}


/// Invalidate the layout of the FlowLayout, it's mandatory for the rotation
override func viewWillLayoutSubviews() {
    theFlowLayout.invalidateLayout()
    super.viewWillLayoutSubviews()
}


/// Set the size of the items (mandatory for the rotation)
override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    theFlowLayout.itemSize = theCollectionView.frame.size
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM