ios 具有可读内容宽度的UICollectionViewController流布局

6l7fqoea  于 2023-03-31  发布在  iOS
关注(0)|答案(3)|浏览(205)

我有一个使用流布局的UICollectionView,我试图实现与具有可读内容宽度的UITableViewController相同的边距。
最接近这种布局行为的方法是将UICollectionViewController嵌入到UIViewController中,并具有嵌入式视图“Follow Readable Width”。

这里蓝绿色是UIViewController,鲑鱼色是UICollectionViewController。问题是蓝绿色区域没有滚动UICollectionView,滚动指示器也没有像你期望的那样沿着屏幕边缘。
我的问题是:
如何在不嵌入UICollectionViewController的情况下实现这种布局?
我的猜测是,我可以通过某种方式设置UICollectionView左右部分的插图,以匹配可读的内容指南边距,并通过覆盖viewWillTransition(to size: with coordinator:)和观察UIContentSizeCategoryDidChange通知来更新它们,但我不知道如何做到这一点。

zbq4xfa0

zbq4xfa01#

为了解决Swift 5.1和iOS 13的问题,你可以将flow layout的sectionInsetReference属性设置为.fromContentInset,将collection view的insetsLayoutMarginsFromSafeArea属性设置为false,并将collection view的contentInset s设置为匹配viewreadableContentGuide的insets。
下面的示例代码显示了一个可能的实现,以便拥有一个具有可读内容宽度的集合视图:

  • ViewController.swift*
import UIKit

class ViewController: UIViewController {

    let collectionView = UICollectionView(
        frame: .zero,
        collectionViewLayout: ColumnFlowLayout(cellsPerRow: 5)
    )
    var collectionViewNeedsLayout = true

    override func viewDidLoad() {
        super.viewDidLoad()

        title = "Demo"

        view.addSubview(collectionView)
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            collectionView.topAnchor.constraint(equalTo: view.topAnchor),
            collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
        ])

        collectionView.backgroundColor = .white
        collectionView.insetsLayoutMarginsFromSafeArea = false
        collectionView.dataSource = self
        collectionView.register(Cell.self, forCellWithReuseIdentifier: "Cell")
    }

    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()

        if collectionViewNeedsLayout {
            let margin = view.readableContentGuide.layoutFrame.origin.x
            collectionView.contentInset.left = margin
            collectionView.contentInset.right = margin
            collectionViewNeedsLayout = false
        }
    }

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

}
extension ViewController: UICollectionViewDataSource {

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

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Cell
        return cell
    }

}
  • ColumnFlowLayout.swift*
import UIKit

class ColumnFlowLayout: UICollectionViewFlowLayout {

    let cellsPerRow: Int

    init(cellsPerRow: Int) {
        self.cellsPerRow = cellsPerRow

        super.init()

        self.sectionInsetReference = .fromContentInset
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func prepare() {
        super.prepare()

        guard let collectionView = collectionView else { return }

        let marginsAndInsets = collectionView.contentInset.left + collectionView.contentInset.right + sectionInset.left + sectionInset.right + minimumInteritemSpacing * CGFloat(cellsPerRow - 1)
        let itemWidth = ((collectionView.bounds.width - marginsAndInsets) / CGFloat(cellsPerRow)).rounded(.down)
        itemSize = CGSize(width: itemWidth, height: itemWidth)
    }

}
  • 手机快 *
import UIKit

class Cell: UICollectionViewCell {

    override init(frame: CGRect) {
        super.init(frame: frame)

        contentView.backgroundColor = .orange
    }

    required init?(coder: NSCoder) {
        fatalError("not implemnted")
    }

}

在iPhone 11 Pro Max上显示:

eivgtgni

eivgtgni2#

你的直觉是正确的,最简单的方法是通过集合视图的insetForSection。根据我的经验,需要以下内容:

  • 返回集合视图的directionalLayoutMargins作为插入(使用.leading和. trailing
  • 通过collectionView.insetsLayoutMarginsFromSafeArea = false禁用自动安全区处理
  • 使用view.readableContentGuide.layoutFrame.origin.x手动设置集合视图的directionalLayoutMargins。请注意,我使用的是 view.readableContentGuide,而不是collectionView
  • 每当viewLayoutMarginsDidChange执行以下操作时,以完全相同的方式更新directionalLayoutMargins

如果知道如何在没有任何类型的容器的情况下实现这一点,那就太好了

3qpi33ja

3qpi33ja3#

在iOS 14+上,如果数据源是可区分的,则可以使用section.contentInsetsReference = .readableContent
这将调整部分插图并遵循可读指南。

相关问题