iOS UICollectionView水平滚动矩形布局,里面的物品大小不一样?

问题描述 投票:0回答:1

iOS UICollectionView如何创建水平滚动的矩形布局,里面的项目大小不同。

我想用UICollectionView创建一个类似下面的矩形布局,如何实现?

当我滚动 横向 使用 采集视图 1,2,3,4,5,6格会一起滚动带来7。

下面是320*480的iPhone分辨率的尺寸。更新后的画面如下。

enter image description here

前6个项目的尺寸与iPhone 5s的尺寸相同。

Item 1 Size is - (213*148)
Item 2 Size is - (106*75)
Item 3 Size is - (106*74)
Item 4 Size is - (106*88)
Item 5 Size is - (106*88)
Item 6 Size is - (106*88)

第6项之后的尺寸与集合视图的宽度和高度相同,如下图。

Item 7 Size is - (320*237)
Item 8 Size is - (320*237)
Item 9 Size is - (320*237)

如何创建一个简单的自定义布局使用集合视图,有水平滚动?

必须感谢一个快速的解决方案。先谢谢了。

ios swift uicollectionview horizontal-scrolling uicollectionviewflowlayout
1个回答
1
投票

我建议在CollectionViewCell(固定尺寸)内使用StackView来创建一个网格布局,如你的帖子所示。

如下图 GridStackView 根据添加的视图数量,使用方法--------创建动态网格布局。addCell(view: UIView).

加此 GridStackView 作为你的CollectionViewCell的唯一子视图,将所有的边缘钉在边上,这样它就能完全填满CollectionViewCell。

在准备你的CollectionViewCell时,使用以下方法为它添加平铺视图 addCell(view: UIView).

如果只添加了一个视图,那么它将显示一个视图占据整个 GridStackView 如果添加了多个视图,它会自动将它们布局在CollectionViewCell内部。

你可以调整下面的代码,通过计算行和列来获得想要的布局。当前需要的实现 rowSize 在初始化的时候提供,我在我的一个项目中使用了,你需要修改一下以获得你想要的布局。

class GridStackView: UIStackView {
    private var cells: [UIView] = []
    private var currentRow: UIStackView?
    var rowSize: Int = 3
    var defaultSpacing: CGFloat = 5

    init(rowSize: Int) {
        self.rowSize = rowSize
        super.init(frame: .zero)
        translatesAutoresizingMaskIntoConstraints = false
        axis = .vertical
        spacing = defaultSpacing
        distribution = .fillEqually
    }

    required init(coder: NSCoder) {
        super.init(coder: coder)
        translatesAutoresizingMaskIntoConstraints = false
        axis = .vertical
        spacing = defaultSpacing
        distribution = .fillEqually
    }

    private func preapreRow() -> UIStackView {
        let row = UIStackView(arrangedSubviews: [])
        row.spacing = defaultSpacing
        row.translatesAutoresizingMaskIntoConstraints = false
        row.axis = .horizontal
        row.distribution = .fillEqually
        return row
    }

    func removeAllCell() {
        for item in arrangedSubviews {
            item.removeFromSuperview()
        }
        cells.removeAll()
        currentRow = nil
    }

    func addCell(view: UIView) {
        let firstCellInRow = cells.count % rowSize == 0
        if currentRow == nil || firstCellInRow {
            currentRow = preapreRow()
            addArrangedSubview(currentRow!)
        }
        view.translatesAutoresizingMaskIntoConstraints = false
        cells.append(view)
        currentRow?.addArrangedSubview(view)
        setNeedsLayout()
    }
}

Layout with current implementation


0
投票

我已经尝试过用 马汉的回答 我得到了部分正确的输出。但问题是,index1有两个项目的全宽。

如何将索引1分割成索引1和索引2?

enter image description here

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        setUpCollectionView()
        // Do any additional setup after loading the view.
    }
    func setUpCollectionView() {
        self.view.backgroundColor = .white
        let layout = UICollectionViewFlowLayout()
//        layout.minimumInteritemSpacing = 1
//        layout.minimumLineSpacing = 1
        layout.scrollDirection = .horizontal
        let collectionView = CollectionView(frame: .zero, collectionViewLayout: layout)
        view.addSubview(collectionView)
        collectionView.bounces = false
        collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
        collectionView.heightAnchor.constraint(equalToConstant: 240).isActive = true
        collectionView.translatesAutoresizingMaskIntoConstraints = false
    }

}
class CollectionView: UICollectionView {
    override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
        super.init(frame: frame, collectionViewLayout: layout)
        self.register(CollectionViewCell.self, forCellWithReuseIdentifier: CollectionViewCell.identifier)
        self.dataSource = self
        self.delegate = self
        self.isPagingEnabled = true

    }

    required init?(coder: NSCoder) {
        fatalError()
    }

}
extension CollectionView: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 10
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CollectionViewCell.identifier, for: indexPath) as! CollectionViewCell
        cell.backgroundColor = .blue
        cell.label.text = "\(indexPath.row)"

        let row = indexPath.row
        switch row {
        case 0:
            cell.backgroundColor = .red
        case 1:
            cell.backgroundColor = .blue
        case 2:
            cell.backgroundColor = .purple
        case 3:
            cell.backgroundColor = .orange
        case 4:
            cell.backgroundColor = .cyan
        case 5:
            cell.backgroundColor = .green
        case 6:
            cell.backgroundColor = .magenta
        case 7:
            cell.backgroundColor = .white
        case 8:
            cell.backgroundColor = .blue
        case 9:
            cell.backgroundColor = .green
        default:
            cell.backgroundColor = .systemPink
        }
        return cell
    }


}

extension  CollectionView: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let row = indexPath.row
        let width = collectionView.frame.width
        let other = width / 3

        let height = collectionView.frame.height
        let o_height =  height / 3
        switch row {
        case 0:
            return CGSize(width: other * 2, height: o_height * 2)
        case 1:
            return CGSize(width: other * 2, height: o_height)
        case 2:
            return CGSize(width: other, height: o_height)
        case 3:
            return CGSize(width: other, height: o_height)
        case 4:
            return CGSize(width: other, height: o_height)
        case 5, 6, 7:
            return CGSize(width: other, height: o_height)
        default:
            return CGSize(width: width, height: height)
        }
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return .leastNormalMagnitude
    }
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return .leastNormalMagnitude
    }
}



class CollectionViewCell: UICollectionViewCell {
    static let identifier = "CollectionViewCell"

    let label = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.contentView.addSubview(label)
        label.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
        label.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
        label.translatesAutoresizingMaskIntoConstraints = false
    }

    required init?(coder: NSCoder) {
        fatalError()
    }
}

如何把index1分成index1和index2,如下图所示?

先谢谢你

enter image description here


0
投票
  • 新建一个单元格,其中包含两个视图。视图的宽度相等。
  • 据此构建你的数据

数据

struct ItemData {
    var color: [UIColor]
}

// NOTICE: 2nd item contains two colors and the rest one.
let data = [ItemData(color: [.red]), ItemData(color: [.blue, .purple]), ItemData(color: [.orange]),
            ItemData(color: [.cyan]), ItemData(color: [.green]), ItemData(color: [.magenta]),
            ItemData(color: [.systemPink]), ItemData(color: [.link]), ItemData(color: [.purple])] 

细胞

class CollectionViewCellOne: UICollectionViewCell {
    static let identifier = "CollectionViewCellOne"

    var item: ItemData? {
        didSet {
            if let item = item {
                self.leadingLabel.backgroundColor = item.color.first!
                self.trailingLabel.backgroundColor = item.color.last!
            }
        }
    }

    let leadingLabel = UILabel()
    let trailingLabel = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.contentView.addSubview(leadingLabel)
        self.contentView.addSubview(trailingLabel)

        let width = self.frame.width / 2

        leadingLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
        leadingLabel.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
        leadingLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
        leadingLabel.widthAnchor.constraint(equalToConstant: width).isActive = true
        leadingLabel.translatesAutoresizingMaskIntoConstraints = false

        trailingLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
        trailingLabel.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
        trailingLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
        trailingLabel.widthAnchor.constraint(equalToConstant: width).isActive = true
        trailingLabel.translatesAutoresizingMaskIntoConstraints = false

    }

    required init?(coder: NSCoder) {
        fatalError()
    }
}

dequeueReusableCell

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    if indexPath.row == 1 {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CollectionViewCellOne.identifier, for: indexPath) as! CollectionViewCellOne
        cell.item = data[indexPath.row]
        return cell
    } else {

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CollectionViewCell.identifier, for: indexPath) as! CollectionViewCell
        if let color = data[indexPath.row].color.first {
            cell.backgroundColor = color
        }

        return cell
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.