时间:2018-02-24 18:26:24

标签: ios swift uicollectionview autolayout uicollectionviewflowlayout

请参阅以下每个项目的边界(边界间距)

enter image description here

使用集合视图Header我能够实现以下输出,但坚持如何将分隔符放在uicollection视图中。行内的单元格数也是动态的。

和最后一行不应该是底部分隔符 任何帮助都非常感谢..

对于实现以下布局,我只使用带有节标题的集合视图 我已经完成了以下输出

所有部分都已折叠

enter image description here 点击了特定的部分

enter image description here

每个展开的部分只剩下分隔符部分 我无法弄清楚如何使用装饰视图实现相同的效果。

3 个答案:

答案 0 :(得分:2)

你可以这样做,

  • 创建两种不同类型的装饰视图,一种用于垂直线,位于集合视图的中心,另一种是水平,位于两个单元格下方
  • 垂直装饰视图仅为整个视图创建一次,而水平装饰视图则为每对下方显示的一对两个创建。对于最后一行,不要创建装饰视图。
  • 子类UICollectionViewFlowLayout,并覆盖覆盖func layoutAttributesForElements(在rect:CGRect中) - > [UICollectionViewLayoutAttributes]?并返回相应的装饰视图。

以下是布局寻找的方式,

enter image description here

以下是用于此的代码,

<强> CollectionViewController

class ViewController: UICollectionViewController {

    let images = ["Apple", "Banana", "Grapes", "Mango", "Orange", "Strawberry"]

     init() {
        let collectionViewLayout = DecoratedFlowLayout()
        collectionViewLayout.register(HorizontalLineDecorationView.self,
                                      forDecorationViewOfKind: HorizontalLineDecorationView.decorationViewKind)
        collectionViewLayout.register(VerticalLineDecorationView.self,
                                      forDecorationViewOfKind: VerticalLineDecorationView.decorationViewKind)
        super.init(collectionViewLayout: collectionViewLayout)
    }

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

    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView?.backgroundColor = UIColor.white
        collectionView?.register(CollectionViewCell.self,
                                 forCellWithReuseIdentifier: CollectionViewCell.CellIdentifier)
    }
}

extension ViewController: UICollectionViewDelegateFlowLayout {

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return images.count
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CollectionViewCell.CellIdentifier,
                                                      for: indexPath) as! CollectionViewCell
        let name = images[indexPath.item]
        cell.imageView.image = UIImage(named: "\(name).png")
        cell.label.text = name
        return cell
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return .zero
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 10 + DecoratedFlowLayout.horizontalLineWidth
    }

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

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

        let width = (collectionView.bounds.size.width - DecoratedFlowLayout.verticalLineWidth)  * 0.5
        return CGSize(width: width,
                      height: width + 20)
    }
}

<强> CollectionViewCell

class CollectionViewCell: UICollectionViewCell {

    static let CellIdentifier = "CollectionViewCellIdentifier"

    var imageView: UIImageView!
    var label: UILabel!

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

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

    func createViews() {
        imageView = UIImageView(frame: .zero)
        imageView.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(imageView)

        label = UILabel(frame: .zero)
        label.font = UIFont.systemFont(ofSize: 20)
        label.textAlignment = .center
        label.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(label)

        NSLayoutConstraint.activate([
            imageView.topAnchor.constraint(equalTo: contentView.topAnchor),
            imageView.leftAnchor.constraint(equalTo: contentView.leftAnchor),
            imageView.rightAnchor.constraint(equalTo: contentView.rightAnchor),
            label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
            label.leftAnchor.constraint(equalTo: contentView.leftAnchor),
            label.rightAnchor.constraint(equalTo: contentView.rightAnchor),
            label.topAnchor.constraint(equalTo: imageView.bottomAnchor),
            label.heightAnchor.constraint(equalToConstant: 20)
            ])
    }
}

<强> DecoratedFlowLayout

class DecoratedFlowLayout: UICollectionViewFlowLayout {

    static let verticalLineWidth: CGFloat = 20
    static let horizontalLineWidth: CGFloat = 20

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        minimumLineSpacing = 40 // should be equal to or greater than horizontalLineWidth 
    }

    override init() {
        super.init()
        minimumLineSpacing = 40
   }

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {

        guard let attributes = super.layoutAttributesForElements(in: rect) else {
            return nil
        }

        var attributesCopy: [UICollectionViewLayoutAttributes] = []

        for attribute in attributes {

            attributesCopy += [attribute]

            let indexPath = attribute.indexPath

            if collectionView!.numberOfItems(inSection: indexPath.section) == 0 {
                continue
            }

            let firstCell = IndexPath(item: 0,
                                      section: indexPath.section)
            let lastCell = IndexPath(item: collectionView!.numberOfItems(inSection: indexPath.section) - 1,
                                     section: indexPath.section)

            if let attributeForFirstItem = layoutAttributesForItem(at: firstCell),
                let attributeForLastItem = layoutAttributesForItem(at: lastCell) {


                let verticalLineDecorationView = UICollectionViewLayoutAttributes(forDecorationViewOfKind: VerticalLineDecorationView.decorationViewKind,
                                                                                  with: IndexPath(item: 0, section: indexPath.section))

                let firstFrame = attributeForFirstItem.frame
                let lastFrame = attributeForLastItem.frame

                let frame = CGRect(x: collectionView!.bounds.midX - DecoratedFlowLayout.verticalLineWidth * 0.5,
                                   y: firstFrame.minY,
                                   width: DecoratedFlowLayout.verticalLineWidth,
                                   height: lastFrame.maxY - firstFrame.minY)
                verticalLineDecorationView.frame =  frame

                attributesCopy += [verticalLineDecorationView]
            }


            let contains = attributesCopy.contains { layoutAttribute in
                layoutAttribute.indexPath == indexPath
                    && layoutAttribute.representedElementKind == HorizontalLineDecorationView.decorationViewKind
            }

            let numberOfItemsInSection = collectionView!.numberOfItems(inSection: indexPath.section)

            if indexPath.item % 2 == 0 && !contains  && indexPath.item < numberOfItemsInSection - 2 {

                let horizontalAttribute = UICollectionViewLayoutAttributes(forDecorationViewOfKind: HorizontalLineDecorationView.decorationViewKind,
                                                                           with: indexPath)

                let frame = CGRect(x: attribute.frame.minX,
                                   y: attribute.frame.maxY + (minimumLineSpacing - DecoratedFlowLayout.horizontalLineWidth) * 0.5,
                                   width: collectionView!.bounds.width,
                                   height: DecoratedFlowLayout.horizontalLineWidth)

                horizontalAttribute.frame = frame

                attributesCopy += [horizontalAttribute]
            }
        }
        return attributesCopy
    }

    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
        return true
    }
}

装饰视图

class VerticalLineDecorationView: UICollectionReusableView {

    static let decorationViewKind = "VerticalLineDecorationView"

    let verticalInset: CGFloat = 40

    let lineWidth: CGFloat = 4.0

    let lineView = UIView()

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

        lineView.backgroundColor = .black

        addSubview(lineView)

        lineView.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint.activate([
            lineView.widthAnchor.constraint(equalToConstant: lineWidth),
            lineView.topAnchor.constraint(equalTo: topAnchor, constant: verticalInset),
            lineView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -verticalInset),
            lineView.centerXAnchor.constraint(equalTo: centerXAnchor),
            ])
    }

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


class HorizontalLineDecorationView: UICollectionReusableView {

    let horizontalInset: CGFloat = 20

    let lineWidth: CGFloat = 4.0

    static let decorationViewKind = "HorizontalLineDecorationView"

    let lineView = UIView()

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

        lineView.backgroundColor = .black

        addSubview(lineView)

        lineView.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint.activate([
            lineView.heightAnchor.constraint(equalToConstant: lineWidth),
            lineView.leftAnchor.constraint(equalTo: leftAnchor, constant: horizontalInset),
            lineView.rightAnchor.constraint(equalTo: rightAnchor, constant: -horizontalInset),
            lineView.centerYAnchor.constraint(equalTo: centerYAnchor),
            ])
    }

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

我希望你可以利用它并调整价值以满足你自己的需要。一些计算可能有意义改变到某种程度。但是,我希望你能够了解如何实现这一目标。

答案 1 :(得分:0)

如果列数始终为2,为什么不向单元格添加三个视图(分隔符),两个侧面和一个底部。对于右侧的单元格,隐藏最右侧的分隔符,反之亦然,左侧的单元格。 隐藏底部的分隔符以查看最后一行的单元格。 这有点像黑客,但实施起来要简单得多。

答案 2 :(得分:0)

自定义UICollectionviewcell(我想你可能已经这样做了), 现在在自定义UICollectionviewcell上放两个UIView -

  • 单元格右侧的一个UIView,宽度为1或2(按照 必需)和高度等于单元格高度,给出黑色背景 颜色为UIView
  • 单元格底部的另一个UIView,具有1或2个点高度(根据需要),此时间宽度等于单元格宽度,为UIView提供黑色背景颜色。 并调整空间。 我觉得这个技巧对你有用。