UICollectionView - 调整设备上的单元格旋转 - Swift

Ben*_*Ben 46 resize rotation uicollectionview swift

我已经创建了一个UICollectionView,这样我就可以将视图排列成整齐的列.我希望在> 500像素宽的设备上有一个列.

为了实现这一点,我创建了这个函数:

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    let size = collectionView.frame.width
    if (size > 500) {
        return CGSize(width: (size/2) - 8, height: (size/2) - 8)
    }
    return CGSize(width: size, height: size)
}
Run Code Online (Sandbox Code Playgroud)

这在第一次加载时按预期工作,但是当我旋转设备时,计算并不总是再次发生,并且视图并不总是按预期重绘.这是设备旋转时的代码:

override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
    collectionView.collectionViewLayout.invalidateLayout()
    self.view.setNeedsDisplay()
}
Run Code Online (Sandbox Code Playgroud)

我假设我忘了重绘一些东西,但我不确定是什么.任何想法都非常感谢收到!

val*_*ine 65

也许最直接的方法是在viewWillTransitionToSize期间使invalidateLoutout:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    guard let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else {
        return
    }
    flowLayout.invalidateLayout()
}
Run Code Online (Sandbox Code Playgroud)

  • 当viewcontroller是未折叠的splitviewcontroller的detailcontroller时,不会调用此方法. (3认同)

ado*_*srs 18

你可能会用viewWillLayoutSubviews.这个问题应该是有用的,但只要视图控制器视图即将布局其子视图,就会以低音方式调用此问题.

所以你的代码看起来像这样:

override func viewWillLayoutSubviews() {
  super.viewWillLayoutSubviews()

  guard let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else {
    return
  }

  if UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication().statusBarOrientation) {
    //here you can do the logic for the cell size if phone is in landscape
  } else {
    //logic if not landscape 
  }

  flowLayout.invalidateLayout()
}
Run Code Online (Sandbox Code Playgroud)

  • 通过使用此方法,您将进入无限循环. (17认同)
  • 我不确定@valvoline是否正确,这将导致无限循环 - 但是它可能会导致性能问题,因为它使收集视图布局失效的频率远远超过必要.使用`viewWillTransitionToSize`要好得多. (5认同)
  • 此代码导致无限循环.这不应该是正确的答案. (5认同)
  • 使用此解决方案时,应用程序会无限循环 (3认同)
  • 这应该没有标记为正确,并替换为`viewWillTransitionToSize`方法. (2认同)

小智 14

我倾向于使用viewWillTransitionToSize相同的东西,只是invalidateLayout()在那里打电话.


Nik*_*rya 9

我使用了以下方法,这对我有用。我的问题是我使布局无效

viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)

但此时(正如此方法名称所暗示的)设备尚未旋转。所以这个方法将在之前被调用viewWillLayoutSubviews,因此在这个方法中我们没有正确的边界和框架(安全区域),因为设备将在之后旋转。

所以我使用了通知

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()
}
Run Code Online (Sandbox Code Playgroud)

然后在集合视图流委托方法中一切都按预期工作。

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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Gra*_*rks 8

要使集合视图调整其单元格的大小并在旋转过程中使更改生效,请使用过渡协调器:

(迅捷4+)

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

    // Have the collection view re-layout its cells.
    coordinator.animate(
        alongsideTransition: { _ in self.collectionView.collectionViewLayout.invalidateLayout() },
        completion: { _ in }
    )
}
Run Code Online (Sandbox Code Playgroud)


bir*_*rdy 5

traitCollectionDidChange也可以使用方法代替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()
}
Run Code Online (Sandbox Code Playgroud)