4

I have a gradient background for my collection view cell and each gradient is different depending on what tag the cell is (e.g Christmas is a purple gradient, birthday is a green gradient) however when scrolling through the collection view, the gradients keep on changing cells. is there a way to fix this from happening?

this is the code I use to set the gradient to the background view. it is in cellForItemAt

cell.mainView.setGradientBackground(colours: self.getColourFromTag(tag: self.lists[indexPath.item].tag))

.setGradientBackground is an extension of UIView which just sets a gradient to the background. shown here:

func setGradientBackground(colours: [CGColor]) {

    let gradientLayer = CAGradientLayer()
    gradientLayer.frame = bounds
    gradientLayer.colors = colours
    gradientLayer.locations = [0.0, 1.0]
    gradientLayer.startPoint = CGPoint(x: 1.0, y: 1.0)
    gradientLayer.endPoint = CGPoint(x: 0.0, y: 0.0)
    layer.insertSublayer(gradientLayer, at: 0)
}

I use the method below to get what colours are in the gradient

func getColourFromTag(tag: String) -> [CGColor] {

    if tag == "Christmas" {

        return [Colours.gradients.festive.start.cgColor, Colours.gradients.festive.end.cgColor]

    }else if tag == "Birthday" {

        return [Colours.gradients.lime.start.cgColor, Colours.gradients.lime.end.cgColor]

    }else if tag == "Valentines Day" {

        return [Colours.gradients.strawberry.start.cgColor, Colours.gradients.strawberry.end.cgColor]

    }else if tag == "Charity" {

        return [Colours.gradients.blueberry.start.cgColor, Colours.gradients.blueberry.end.cgColor]

    }else if tag == "Event" {

        return [Colours.gradients.fire.start.cgColor, Colours.gradients.fire.end.cgColor]

    }else{
        return [Colours.gradients.midnight.start.cgColor, Colours.gradients.midnight.end.cgColor]
    }
}

I have tried appending each [colour] into an array, then placing that into the .setGradientBackground at the indexPath.item like so:

var colours = [[CGColor]]()

colours[indexPath.item] = self.getColourFromTag(tag: self.lists[indexPath.item].tag)
cell.mainView.setGradientBackground(colours: colours[indexPath.item])

however, this does not work since it is out of range. Does anyone have a solution? thank you.

Andrew Harris
  • 396
  • 7
  • 24
  • And what does `setGradientBackground()`? – Larme Dec 03 '18 at 15:30
  • I have edited the question to show that code :) – Andrew Harris Dec 03 '18 at 15:31
  • Cells are reused and you do each time `layer.insertSublayer(gradientLayer, at: 0)`. So with the reuse, if the cell had a previous layer, it will be: layer at 0: new gradient, layer at 1: previous layer, etc. Remove the previous layer if found as a `CAGradientLayer` – Larme Dec 03 '18 at 15:33
  • thanks for the reply, how would I do this exactly? (remove the layer if found) – Andrew Harris Dec 03 '18 at 15:35
  • `layer.sublayers.filter(where: {$0 as? CAGradient}).forEach{$0.removeFromSuperlayer}`? – Larme Dec 03 '18 at 15:37

1 Answers1

5

Reading your code in setGradientBackground(), you always init a new CAGradientLayer and insert it at the lowest position in your cell. Every time setGradientBackground() gets called again, the new gradient layer will be positioned below all other gradients you already inserted.

Try to get a already existing CAGradientLayer from sublayers and set the new colors.

    var gradientLayer = CAGradientLayer()
    if let sublayers = layer.sublayers {
        for sublayer in sublayers {
            if let gLayer = sublayer as? CAGradientLayer {
                gradientLayer = gLayer
                break
            }
        }
    }
    gradientLayer.frame = bounds
    gradientLayer.colors = colours
    gradientLayer.locations = [0.0, 1.0]
    gradientLayer.startPoint = CGPoint(x: 1.0, y: 1.0)
    gradientLayer.endPoint = CGPoint(x: 0.0, y: 0.0)
    layer.insertSublayer(gradientLayer, at: 0)

EDIT

This is a more swift like version (Swift 4.2) using compactMap() for getting the first existing gradient layer in layer.sublayers:

if let existingLayer = (layer.sublayers?.compactMap { $0 as? CAGradientLayer })?.first {
    gradientLayer = existingLayer
}
Rainer Schwarz
  • 380
  • 3
  • 9