I\'ve created a UICollectionView, so that I can arrange views into neat columns. I\'d like there to be a single column on devices > 500 pixels wide.
In order to achi
traitCollectionDidChange
method might be used as well instead of viewWillLayoutSubviews
:
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
guard let previousTraitCollection = previousTraitCollection, traitCollection.verticalSizeClass != previousTraitCollection.verticalSizeClass ||
traitCollection.horizontalSizeClass != previousTraitCollection.horizontalSizeClass else {
return
}
if traitCollection.horizontalSizeClass == .regular && traitCollection.verticalSizeClass == .regular {
// iPad portrait and landscape
// do something here...
}
if traitCollection.horizontalSizeClass == .compact && traitCollection.verticalSizeClass == .regular {
// iPhone portrait
// do something here...
}
if traitCollection.horizontalSizeClass == .regular && traitCollection.verticalSizeClass == .compact {
// iPhone landscape
// do something here...
}
collectionView?.collectionViewLayout.invalidateLayout()
collectionView?.reloadData()
}
I have used following approach, which worked for me. Problem with me was that I was invalidating layout in
viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)
But at this point (as this method name suggest) Device has not been rotated yet.
So this method will be called before viewWillLayoutSubviews
and hence in this method we do not have right bounds and frames (Safe Area) as device will rotate afterwards.
So I used notifications
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(rotated), name: UIDevice.orientationDidChangeNotification, object: nil)
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
NotificationCenter.default.removeObserver(self, name: UIDevice.orientationDidChangeNotification, object: nil)
}
@objc func rotated(){
guard let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else {
return
}
flowLayout.invalidateLayout()
}
and then in collection view flow delegate method everything works as expected.
extension ViewController: UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize{
if #available(iOS 11.0, *) {
return CGSize(width: view.safeAreaLayoutGuide.layoutFrame.width, height: 70)
} else {
return CGSize(width: view.frame.width, height: 70)
}
}
}
This is for others with maybe same special case.
Situation:
I included a UICollectionView
as a UITableViewCell
in a table view controller. The row height was set to UITableViewAutomaticDimension
to adapt on number of cells in the collection view. It didn't layout correctly on device rotation although other cells with dynamic content in the same table view behaved correctly. After a long research I found a solution that worked:
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[self reloadTableViewSilently];
}
- (void) reloadTableViewSilently {
dispatch_async(dispatch_get_main_queue(), ^{
// optional: [UIView setAnimationsEnabled:false];
[self.tableView beginUpdates];
[self.tableView endUpdates];
// optional: [UIView setAnimationsEnabled:true];
});
}