【问题标题】:UICollectionViewController flow layout with readable content width具有可读内容宽度的 UICollectionViewController 流布局
【发布时间】:2018-01-15 01:50:31
【问题描述】:

我有一个使用流式布局的UICollectionView,我正在尝试实现与具有可读内容宽度的UITableViewController 相同的边距。

我最接近匹配此布局行为的方法是将 UICollectionViewController 嵌入到 UIViewController 中,并让嵌入的视图“跟随可读宽度”。

这里的蓝绿色是UIViewController,鲑鱼色是UICollectionViewController。问题是青色区域没有滚动UICollectionView,并且滚动指示器也不像您期望的那样沿着屏幕边缘。

我的问题是:

如何在不嵌入UICollectionViewController 的情况下实现此布局?

我的猜测是,我可以以某种方式设置 UICollectionView 左右部分插入以匹配可读内容指南边距并通过覆盖 viewWillTransition(to size: with coordinator:) 并观察 UIContentSizeCategoryDidChange 通知来更新它们,但我不知道如何去吧。

【问题讨论】:

  • 您显示的图像没有足够的内容滚动,所以不清楚(对我来说,无论如何)问题是什么。也许还可以发布您希望它的外观的图片?
  • 他希望红色集合视图看起来与上面完全相同,但不使用青色视图控制器作为容器 - 例如通过使用部分插图来缩小宽度以匹配可读的内容指南。

标签: ios uicollectionview


【解决方案1】:

你的预感是正确的,最简单的方法是通过集合视图的insetForSection。根据我的经验,以下是必需的:

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

知道如何在没有任何类型的容器的情况下完成此操作仍然很好

【讨论】:

    【解决方案2】:

    为了解决您使用 Swift 5.1 和 iOS 13 的问题,您可以将流布局的 sectionInsetReference 属性设置为 .fromContentInset,将集合视图的 insetsLayoutMarginsFromSafeArea 属性设置为 false,并将集合视图的 @987654324 设置为@s 匹配 viewreadableContentGuide 的插图。


    以下示例代码显示了一个可能的实现,以便拥有一个具有可读内容宽度的集合视图:

    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)
        }
    
    }
    

    Cell.swift

    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 上显示:

    【讨论】:

      猜你喜欢
      • 2013-03-10
      • 2019-06-22
      • 2019-07-19
      • 1970-01-01
      • 2017-04-14
      • 2012-01-17
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多