如何为集合视图创建堆栈视图效果?

How to create effect of stack of view for collection view?

我正在尝试为集合视图创建像少数视图堆栈那样的效果,我过去不是这样构建效果的,无法理解如何在没有图像的情况下以编程方式创建这种效果?

有人可以向我解释如何重复此效果或 post link 教程代码吗?

下面这个效果的例子:

要获得这种效果,您需要在集合视图单元格的层下添加层,这些层更小并且从单元格的层向下移动一点。您将使用与具有比单元格层更低 alpha 的每一层上的单元格相同的背景颜色。

我创建了一个演示如何获得效果的示例项目:

https://github.com/DuncanMC/CustomCollectionViewCell.git

单元格如下所示:

繁重的工作在我称为 MyCollectionViewCell

的 UICollectionViewCell 的自定义子 class 中

这是class:

class MyCollectionViewCell: UICollectionViewCell {

    public var contentCornerRadius: CGFloat = 0 {
        didSet {
            contentView.layer.cornerRadius = contentCornerRadius
            sizeLayerFrames()
        }

    }

    public var fraction: CGFloat = 0.075 { // What percent to shrink & shift the faded layers down (0.075 = 7.5%)
        didSet {
            sizeLayerFrames()
        }
    }
    private var layerMask =   CAShapeLayer()
    private var layer1 = CALayer()
    private var layer2 = CALayer()


    // Use this function to set the cell's background color.
    // (You can't set the view's background color, since we Don't clip the view to it's bounds.)

    // Be sure to set the background color explicitly, since by default it sets a random color that will persist
    // as the cells are recylced, causing your cell colors to move around as the user scrolls
    public func setBackgroundColor(_ color: UIColor)  {
        var red: CGFloat = 0
        var green: CGFloat = 0
        var blue: CGFloat = 0
        color.getRed(&red, green: &green, blue: &blue, alpha: nil)
        contentView.layer.backgroundColor = color.cgColor

        //Make the first extra layer have the same color as the cell's layer, but with alpha 0.25
        layer1.backgroundColor = UIColor(red: red, green: green, blue: blue, alpha: 0.25).cgColor

        //Make the second extra layer have the same color as the cell's layer, but with alpha 0.125
        layer2.backgroundColor = UIColor(red: red, green: green, blue: blue, alpha: 0.125).cgColor
    }

    @IBOutlet weak var customLabel: UILabel!

    //Do The initial setup once the cell is loaded.
    //Note that t
    override func awakeFromNib() {
        contentView.layer.masksToBounds = false

        // Color each cell's layer some random hue (change to set whatever color you desire.)
        //For testing, use a color based on a random hue and fairly high random brightness.
        let hue = CGFloat.random(in: 0...360)
        let brightness = CGFloat.random(in: 0.8...1.0)
        layer.masksToBounds = false
        setBackgroundColor(UIColor(hue: hue, saturation: 1, brightness: brightness, alpha: 1))


        // Make the inside of the shape layer white (opaque), The color doesn't matter - just that the alpha value is 1
        // and the outside clear (transparent)
        layerMask.fillColor = UIColor.white.cgColor
        layerMask.backgroundColor = UIColor.clear.cgColor

        //With the even/odd rule, the inner shape will not be filled (we'll only fill the part NOT in the inner shape)
        layerMask.fillRule = .evenOdd
        contentCornerRadius = 30


        sizeLayerFrames()

        contentView.layer.addSublayer(layer1)
        layer1.addSublayer(layer2)
        layer1.mask = layerMask
    }

    private func sizeLayerFrames() {
        layer1.cornerRadius = contentCornerRadius
        layer2.cornerRadius = contentCornerRadius


        let viewBounds = bounds //Use the layer's bounds as the starting point for the extra layers.
        var frame1 = viewBounds
        frame1.origin.y += viewBounds.size.height * fraction
        frame1.origin.x += viewBounds.size.width * fraction

        frame1.size.width *= CGFloat(1 - 2 * fraction)
        layer1.frame = frame1
        var frame2 = viewBounds
        frame2.origin.y += viewBounds.size.height * 0.75 * fraction
        frame2.origin.x += viewBounds.size.width  * fraction

        frame2.size.width *= CGFloat(1 - 4 * fraction)
        layer2.frame = frame2

        //Create a mask layer to clip the extra layers.
        var maskFrame = viewBounds

        //We are going to install the mask on layer1, so offeset the frame to cover the whole view contents
        maskFrame.origin.y -= viewBounds.size.height * fraction
        maskFrame.origin.x -= viewBounds.size.width * fraction
        maskFrame.size.height += viewBounds.size.height * fraction * 1.75
        layerMask.frame = maskFrame
        maskFrame = viewBounds
        let innerPath = UIBezierPath(roundedRect: maskFrame, cornerRadius: 30)
        maskFrame.size.height += viewBounds.size.height * fraction * 1.75
        let combinedPath = UIBezierPath(rect: maskFrame)
        combinedPath.append(innerPath)
        layerMask.path = combinedPath.cgPath
    }

    override var bounds: CGRect {
        didSet {
            sizeLayerFrames()
        }
    }
}