UICollectionView水平分页旋转后不居中

UICollectionView horizontal paging not centring after rotation

我目前正在处理水平画廊滚动视图。我决定使用启用了水平分页的 UICollectionView。它几乎工作得很好......期望在旋转时集合视图单元格不居中(见附图截图),其中红色是第一个单元格,黄色是第二个单元格。

它通常在第一次旋转时工作正常,但随后就搞砸了:D

这是我设置 class:

的代码
class GalleryScrollView: UIView {
    private var collectionView: UICollectionView!
    private var layout: UICollectionViewFlowLayout!
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupView()
    }

    override func layoutSubviews() {
        layout.invalidateLayout()
    }

    private func setupView() {
        layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        collectionView = UICollectionView(frame: self.frame,
                                          collectionViewLayout: layout)
        collectionView.register(UINib(nibName: "PhotoGalleryCell", bundle: nil), forCellWithReuseIdentifier: "photoGalleryCell")
        collectionView.isPagingEnabled = true
        collectionView.contentInsetAdjustmentBehavior = .never
        collectionView.dataSource = self
        collectionView.delegate = self
        collectionView.autoresizingMask = .flexibleWidth
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        collectionView.backgroundColor = .green
        self.addSubview(collectionView)

        NSLayoutConstraint.activate([
            collectionView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
            collectionView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
            collectionView.topAnchor.constraint(equalTo: self.topAnchor),
            collectionView.bottomAnchor.constraint(equalTo: self.bottomAnchor)
        ])

        collectionView.reloadData()
    }
}

接着是集合视图设置:

extension GalleryScrollView: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
    return 0
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoGalleryCell", for: indexPath) as? PhotoGalleryCell else {
        return UICollectionViewCell()
    }

    if indexPath.item == 0 {
        cell.backgroundColor = .red
    } else {
        cell.backgroundColor = .yellow
    }

    return cell
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    2
}

func collectionView(_ collectionView: UICollectionView,
                    layout collectionViewLayout: UICollectionViewLayout,
                    sizeForItemAt indexPath: IndexPath) -> CGSize {
    return self.frame.size
}

我尝试使用 func collectionView(_ collectionView: UICollectionView, targetContentOffsetForProposedContentOffset proposedContentOffset: CGPoint) -> CGPoint {,但由于某种原因,函数从未被调用。

还有其他人 运行 遇到过这个问题吗?我在 objective c 个线程中看到了很多主题,在 swift 中看到的不多。我也有点难以理解为什么会这样,所以仅仅理解这个问题就会很有帮助。谢谢!

您似乎没有处理过轮换。发生旋转时,您需要 reloadData。您将从那里在 UIViewController 中获得事件,您可以在 UICollectionView.

的实例上调用 reloadData
class GalleryViewController: UIViewController {
    //...
    var galleryScrollView: GalleryScrollView
    //...
    override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
        super.willTransition(to: newCollection, with: coordinator)
        galleryScrollView.collectionViewLayout.invalidateLayout()
    }
    //...
}

然后在GalleryScrollView:

class GalleryScrollView: UIView {
    var currentVisibleIndexPath = IndexPath(row: 0, section: 0)
    //....
}

extension GalleryScrollView: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    //...
    func collectionView(_ collectionView: UICollectionView, targetContentOffsetForProposedContentOffset proposedContentOffset: CGPoint) -> CGPoint {
        let attributes =  collectionView.layoutAttributesForItem(at: currentVisibleIndexPath)
        let newOriginForOldIndex = attributes?.frame.origin
        return newOriginForOldIndex ?? proposedContentOffset
    }

    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {

        let center = CGPoint(x: scrollView.contentOffset.x + (scrollView.frame.width / 2), y: (scrollView.frame.height / 2))
        if let indexPath = self.screenView.indexPathForItem(at: center) {
            currentVisibleIndexPath = indexPath
        }
    }
}