UIcollectionView不会在手机旋转时更新UIcollectionCell的大小和布局

时间:2019-10-20 18:52:41

标签: swift

我有一个带有图像的UIcollectionView。当我旋转屏幕时,单元格未按预期调整大小。我尝试将collectionView.collectionViewLayout.invalidateLayout()添加到viewDidLayoutSubviews()-但这只会导致崩溃。有人可以请教吗?

我有一个带有图像的UIcollectionView。当我旋转屏幕时,单元格未按预期调整大小。我尝试将collectionView.collectionViewLayout.invalidateLayout()添加到viewDidLayoutSubviews()-但这只会导致崩溃。有人可以请教吗?

肖像:

enter image description here

风景:

enter image description here

class GridPicksCollectionViewController: UICollectionViewController{

let cellId = "gridyPickCell"
var numCelPerRow: CGFloat = 3
var layout: UICollectionViewFlowLayout!
let borderInset: CGFloat = 3
let interCellSpacing: CGFloat = 3
let spacingBetweenRows: CGFloat = 3
var dataSource = [UIImage]()
var collectionViewWidth: CGFloat!


override func viewDidLoad() {
    super.viewDidLoad()

    generalSetup()
    setUpDateSource()
    setupCollectionViewLayout()
}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    print("viewDidLayoutSubviews")

    // Update collectionViewWidth upon rotation
    collectionViewWidth = self.collectionView.frame.width
    //collectionView.collectionViewLayout.invalidateLayout() - causes app to crash

}

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    print("viewWillTransition")
}


private func generalSetup(){
    navigationController?.navigationBar.barTintColor = UIColor.appDarkGreen
    navigationItem.title = "Girdy Picks"
    let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
    navigationController?.navigationBar.titleTextAttributes = textAttributes
    collectionView.backgroundColor = UIColor.white
    collectionViewWidth = collectionView.frame.width

    // Make sure collectionView is always within the safe area layout
    if #available(iOS 11.0, *) {
        collectionView?.contentInsetAdjustmentBehavior = .always
    }

    // Register UICollectionViewCell
    collectionView.register(GirdyPickCollectionCell.self, forCellWithReuseIdentifier: cellId)
}


private func setUpDateSource(){
    let images: [UIImage] = [UIImage.init(named: "buddha")!, UIImage.init(named: "sharpener")!,  UIImage.init(named: "cars")!, UIImage.init(named: "houses")!, UIImage.init(named: "houses2")!, UIImage.init(named: "tower1")!, UIImage.init(named: "tower2")!]
    dataSource = images

}

private func setupCollectionViewLayout(){
    collectionView.delegate = self
    collectionView.dataSource = self
    layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
    layout.minimumInteritemSpacing = interCellSpacing // distance between cells in a row
    layout.minimumLineSpacing = spacingBetweenRows // distance in between rows
    layout.sectionInset = UIEdgeInsets.init(top: borderInset, left: borderInset, bottom: borderInset, right: borderInset) // border inset for collectionView
}
}


extension GridPicksCollectionViewController: UICollectionViewDelegateFlowLayout{

override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return dataSource.count
}

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! GirdyPickCollectionCell
    cell.imageView.image = dataSource[indexPath.row]
    return cell
}

override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let selectedImage = dataSource[indexPath.row]
    let showImageVC = ImageGridViewController()
    showImageVC.modalPresentationStyle = .fullScreen
    showImageVC.imageToDisplay = selectedImage
    self.present(showImageVC, animated: true) {}
}


// Determine size for UICollectionCell
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    print("sizeForItemAt")
    guard let collectionWidth = collectionViewWidth else{ return CGSize.init()}
    let widthCell = (collectionWidth - interCellSpacing * 2 - borderInset * 2) / numCelPerRow
    return CGSize.init(width: widthCell, height: widthCell)
}
}

1 个答案:

答案 0 :(得分:0)

您错认为事件的生命周期。旋转设备时,您的视图层次结构将收到此事件的通知,并且视图将根据其拥有的信息开始重新布局自己。 完成后,将调用viewDidLayoutSubviews(),而不是之前。

由于您正在使用此方法更新collectionViewWidth属性,因此布局在调用collectionView(_:layout:sizeForItemAt:)时仍使用旧值。您需要在viewWillLayoutSubviews()中设置此值。

或者,您可以为此属性编写一个setter,它将在集合视图的布局上调用invalidateLayout(),但这会导致不必要的布局传递。