【问题标题】:Self sizing UICollectionView with autolayout使用自动布局调整 UICollectionView 的大小
【发布时间】:2021-03-22 01:18:58
【问题描述】:

我想弄清楚 UICollectionView 是否可以使用自动布局计算它自己的高度?我的自定义单元格是基于自动布局构建的,并且 itemSize 的 UICollectionViewFlowLayout.automaticSize 属性似乎正在工作,但应该设置 UICollectionView 本身的大小。我相信这是正常行为,因为集合的大小可能比它的单元格大,但也许可以使 UICollectionView 的内容视图的高度等于带有一些插图的单元格?

这是使用 UICollectionView 测试 UIViewController 的代码

class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
    
    var collectionView: UICollectionView?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .green
        
        let layout = UICollectionViewFlowLayout()
        layout.estimatedItemSize = CGSize(width: UIScreen.main.bounds.width, height: 100)
        layout.itemSize = UICollectionViewFlowLayout.automaticSize
        layout.scrollDirection = .horizontal
        layout.minimumLineSpacing = 0
        layout.minimumInteritemSpacing = 0
        collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)

        
        if let collectionView = collectionView {
            
            collectionView.showsHorizontalScrollIndicator = false
            collectionView.isPagingEnabled = true
            collectionView.register(CollectionViewCell.self,
                                    forCellWithReuseIdentifier: "CollectionViewCell")
            collectionView.backgroundColor = .clear
            collectionView.translatesAutoresizingMaskIntoConstraints = false

            view.addSubview(collectionView)
            collectionView.delegate = self
            collectionView.dataSource = self
            
            NSLayoutConstraint.activate([
                collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
                collectionView.leftAnchor.constraint(equalTo: view.leftAnchor),
                collectionView.rightAnchor.constraint(equalTo: view.rightAnchor),
                // I want to get rid of this constraint
                collectionView.heightAnchor.constraint(equalToConstant: 200)
            ])
        }
    }
    
    
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        5
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell",
                                                            for: indexPath) as? CollectionViewCell else {
            return UICollectionViewCell()
        }
        
        return cell

    }
}

对于自定义单元格

final class CollectionViewCell: UICollectionViewCell {
    
    var mainView = UIView()
    
    var bigView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = .yellow
        return view
    }()
    
    var label: UILabel = {
        let label = UILabel()
        label.text = "Here is text"
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    var anotherLabel: UILabel = {
        let label = UILabel()
        label.text = "Here may be no text"
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    let inset: CGFloat = 16.0
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        addSubview(mainView)
        mainView.translatesAutoresizingMaskIntoConstraints = false
        mainView.backgroundColor = .white
        addSubview(bigView)
        addSubview(label)
        addSubview(anotherLabel)
        
        NSLayoutConstraint.activate([
            mainView.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width),
            mainView.topAnchor.constraint(equalTo: topAnchor),
            mainView.leftAnchor.constraint(equalTo: leftAnchor),
            mainView.rightAnchor.constraint(equalTo: rightAnchor),
            mainView.bottomAnchor.constraint(equalTo: bottomAnchor),
            
            bigView.topAnchor.constraint(equalTo: mainView.topAnchor, constant: inset),
            bigView.leftAnchor.constraint(equalTo: mainView.leftAnchor, constant: inset),
            bigView.rightAnchor.constraint(equalTo: mainView.rightAnchor, constant: -inset),
            bigView.bottomAnchor.constraint(equalTo: mainView.bottomAnchor, constant: -inset),
                        
            label.topAnchor.constraint(equalTo: bigView.topAnchor, constant: inset),
            label.leftAnchor.constraint(equalTo: bigView.leftAnchor, constant: inset),
            label.rightAnchor.constraint(equalTo: bigView.rightAnchor, constant: -inset),
            
            anotherLabel.topAnchor.constraint(equalTo: label.bottomAnchor, constant: inset),
            anotherLabel.leftAnchor.constraint(equalTo: bigView.leftAnchor, constant: inset),
            anotherLabel.rightAnchor.constraint(equalTo: bigView.rightAnchor, constant: -inset),
            anotherLabel.bottomAnchor.constraint(equalTo: bigView.bottomAnchor, constant: -inset)
        ])
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

也许知道答案的人也可以判断是否可以稍后将此分页集合放入 UITalbleViewCell 并使用集合中的选定项目更改单元格的大小?我提供了我正在尝试制作的集合的屏幕截图: 没有第二个文本标签的项目的高度会比图片上的项目小

Screenshot

【问题讨论】:

  • 您的意思是要根据您的内容/单元格设置集合视图大小吗?

标签: ios swift uicollectionview autolayout


【解决方案1】:

解决方案 1: 从 collectionViewLayout 获取集合视图内容大小:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
         // Set your collection view height here.
    let collectionHeight = self.yourCollectionView.collectionViewLayout.collectionViewContentSize.height
  }

解决方案 2: 使用 KVO。

// Register observer 
self.yourCollectionView.addObserver(self, forKeyPath: "contentSize", options: [.new, .old, .prior], context: nil)

@objc override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {        
    if keyPath == "contentSize" {
         // content size changed. Set your collection view height here.
let contentSize = change?[NSKeyValueChangeKey.newKey] as? CGSize {
            print("contentSize:", contentSize)

    }
}

// Remove register observer
 deinit {
        self.yourCollectionView.removeObserver(self, forKeyPath: "contentSize")
    }

解决方案 3: 将此类分配给 UICollectionView。如果您从情节提要设置高度约束,则在运行时设置并启用删除。

class DynamicCollectionView: UICollectionView {
  override func layoutSubviews() {
    super.layoutSubviews()
    if !__CGSizeEqualToSize(bounds.size, self.intrinsicContentSize) {
      self.invalidateIntrinsicContentSize()
    }
  }
   
  override var intrinsicContentSize: CGSize {
    var size = contentSize
    size.height += (contentInset.top + contentInset.bottom)
    size.width += (contentInset.left + contentInset.right)
    return size
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-22
    • 1970-01-01
    • 2014-04-29
    • 1970-01-01
    • 2014-08-19
    相关资源
    最近更新 更多