为 CollectionView 中的部分设置边框

Set border for sections in CollectionView

我想像这样创建集合视图:

问题是我想为每个部分制作一个圆角边框并更改其背景颜色。谁能告诉我怎么做?

您可以通过一些自定义 UICollectionViewLayout 实现这样的 UICollectionView 外观。补充意见可以帮助背景!

我可以建议 SquareMosaicLayout 可以根据您提供的图片进行定制。截图显示,很简单就可以达到想要的外观。它只是缺少单元格之间的边界,但是您可以轻松地自己做。

P.S。我已将您的布局添加到存储库中,因此您可以下载并 运行 项目。

使用 SquareMosaicLayout 的完整代码:

import UIKit
import SquareMosaicLayout

final class Hungcao: UIViewController, UICollectionViewDataSource {

    override func viewDidLoad() {
        super.viewDidLoad()
        let collection = UICollectionView(frame: .zero, collectionViewLayout: HungcaoLayout())
        collection.backgroundColor = UIColor.white
        collection.contentInset = UIEdgeInsets(top: 60.0, left: 20.0, bottom: 10.0, right: 20.0)
        collection.register(UICollectionViewCell.self)
        collection.register(UICollectionReusableView.self, identifier: SquareMosaicLayoutSectionBacker, kind: SquareMosaicLayoutSectionBacker)
        collection.register(UICollectionReusableView.self, identifier: SquareMosaicLayoutSectionHeader, kind: SquareMosaicLayoutSectionHeader)
        collection.dataSource = self
        self.title = "Hungcao"
        self.view = collection
    }

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

    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 2
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell: UICollectionViewCell = collectionView.dequeueCell(indexPath: indexPath)
        cell.contentView.backgroundColor = UIColor.clear

        let label = UILabel()
        label.text = "Cell \(indexPath.row)"
        label.font = UIFont.systemFont(ofSize: 20)
        label.textAlignment = .center
        label.frame = cell.contentView.bounds
        cell.contentView.addSubview(label)

        return cell
    }

    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        switch kind {
        case SquareMosaicLayoutSectionBacker:
            let view: UICollectionReusableView = collectionView.dequeueSupplementary(kind, indexPath: indexPath, kind: kind)
            view.layer.backgroundColor = UIColor.groupTableViewBackground.cgColor
            view.layer.cornerRadius = 10.0
            view.layer.borderWidth = 2.0
            view.layer.borderColor = UIColor.black.cgColor
            return view
        case SquareMosaicLayoutSectionHeader:
            let view: UICollectionReusableView = collectionView.dequeueSupplementary(kind, indexPath: indexPath, kind: kind)
            view.layer.backgroundColor = UIColor.clear.cgColor

            let label = UILabel()
            label.text = "header"
            label.font = UIFont.systemFont(ofSize: 20)
            label.textAlignment = .center
            label.frame = view.bounds
            view.addSubview(label)

            return view
        default:
            fatalError()
        }
    }
}

final class HungcaoLayout: SquareMosaicLayout, SquareMosaicDataSource {

    convenience init() {
        self.init(direction: SquareMosaicDirection.vertical)
        self.dataSource = self
    }

    func layoutPattern(for section: Int) -> SquareMosaicPattern {
        return HungcaoPattern()
    }

    func layoutSupplementaryBackerRequired(for section: Int) -> Bool {
        return true
    }

    func layoutSeparatorBetweenSections() -> CGFloat {
        return 60.0
    }

    func layoutSupplementaryHeader(for section: Int) -> SquareMosaicSupplementary? {
        return HungcaoSupplementary()
    }
}

final class HungcaoSupplementary: SquareMosaicSupplementary {

    func supplementaryFrame(for origin: CGFloat, side: CGFloat) -> CGRect {
        return CGRect(x: 0, y: origin, width: side, height: 60)
    }
}

final class HungcaoPattern: SquareMosaicPattern {

    func patternBlocks() -> [SquareMosaicBlock] {
        return [HungcaoBlock()]
    }
}

public class HungcaoBlock: SquareMosaicBlock {

    public func blockFrames() -> Int {
        return 4
    }

    public func blockFrames(origin: CGFloat, side: CGFloat) -> [CGRect] {
        let width = side / 2.0
        var frames = [CGRect]()
        frames.append(CGRect(x: 0, y: origin, width: width, height: 80))
        frames.append(CGRect(x: width, y: origin, width: width, height: 80))
        frames.append(CGRect(x: 0, y: origin + 80, width: width, height: 80))
        frames.append(CGRect(x: width, y: origin + 80, width: width, height: 80))
        return frames
    }
}

// MARK: - UICollectionViewCell

extension UICollectionView {

    func dequeueCell<T:UICollectionViewCell>(_ identifier: String? = nil, indexPath: IndexPath) -> T {
        let identifier = identifier ?? String(describing: T.self)
        let cell = self.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as? T
        switch cell {
        case .some(let unwrapped):  return unwrapped
        default:                    fatalError("Unable to dequeue" + T.self.description())
        }
    }

    func register<T:UICollectionViewCell>(_ type: T.Type, identifier: String? = nil) {
        let identifier = identifier ?? String(describing: T.self)
        register(type, forCellWithReuseIdentifier: identifier)
    }
}

// MARK: - UICollectionReusableView

extension UICollectionView {

    func dequeueSupplementary<T:UICollectionReusableView>(_ identifier: String? = nil, indexPath: IndexPath, kind: String) -> T {
        let identifier = identifier ?? String(describing: T.self)
        let view = self.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: identifier, for: indexPath) as? T
        switch view {
        case .some(let unwrapped):  return unwrapped
        default:                    fatalError("Unable to dequeue" + T.self.description())
        }
    }

    func register<T:UICollectionReusableView>(_ type: T.Type, identifier: String? = nil, kind: String) {
        let identifier = identifier ?? String(describing: T.self)
        register(type, forSupplementaryViewOfKind: kind, withReuseIdentifier: identifier)
    }
}