safetotry
safetotry

Reputation: 97

Gradient Layer over a CustomImageView

This is my first time trying to apply a gradient layer to a CustomImageView, and to do that within a UICollectionViewCell, I decided to create the following function:

func configureGradientOverlay() {
    
    let maskedView = UIView(frame: CGRect(x: 0, y: 0.5, width: 400, height: 400))
    maskedView.backgroundColor = .black

    let gradientMaskLayer = CAGradientLayer()
    gradientMaskLayer.frame = maskedView.bounds
    gradientMaskLayer.colors = [UIColor.clear.cgColor, UIColor.clear.cgColor, UIColor.clear.cgColor, UIColor.white.cgColor]
    gradientMaskLayer.locations = [0, 0.4, 0.6, 0.99]

    maskedView.layer.mask = gradientMaskLayer
    postImageView.addSubview(maskedView)   
}

This seems to do the trick in applying the gradient overlay over the 'postImageView' but as you can see, I've decided to arbitrarily set the width and height of the 'maskedView' to 400. Ideally, I'd like to set the width and height to those of the 'postImageView' but when I try to do that using the code below, the gradient overlay no longer shows up.

let postImageViewSize: CGRect = postImageView.bounds
let postImageViewWidth = postImageViewSize.width
let postImageViewHeight = postImageViewSize.height

let maskedView = UIView(frame: CGRect(x: 0, y: 0.5, width: postImageViewWidth, height: postImageViewHeight))

Can anyone tell me what I might be doing wrong here?

Upvotes: 0

Views: 125

Answers (2)

Glenn Posadas
Glenn Posadas

Reputation: 13300

Flanker is actually right. So go ahead and set the width and height to those of the 'postImageView'.

func configureGradientOverlay() {
    
    let postImageViewSize: CGRect = postImageView.bounds
    let postImageViewWidth = postImageViewSize.width
    let postImageViewHeight = postImageViewSize.height
  
    let maskedView = UIView(frame: CGRect(x: 0, y: 0.5, width: postImageViewWidth, height: postImageViewHeight))
    maskedView.backgroundColor = .black

    maskedView.layer.mask = gradientMaskLayer
    postImageView.addSubview(maskedView)
}

And then call as well the configureGradientOverlay in layoutSublayers.

override func layoutSublayers(of layer: CALayer) {
    super.layoutSublayers(of: layer)
    
  let gradientMaskLayer = CAGradientLayer()
          gradientMaskLayer.frame = maskedView.bounds
          gradientMaskLayer.colors = [UIColor.clear.cgColor, UIColor.clear.cgColor, UIColor.clear.cgColor, UIColor.white.cgColor]
          gradientMaskLayer.locations = [0, 0.4, 0.6, 0.99]

          maskedView.layer.mask = gradientMaskLayer
}

Voila!

EDIT (aside from the codes), the postImageViewHeight will be ZERO here, unless you calculate the height in didLayoutSubviews() or something.

Upvotes: 0

flanker
flanker

Reputation: 4210

Using a view's bounds within an initialiser is always pot luck as there's no guarantee that the view will be fully drawn when the bounds property is accessed. A better approach is to override the layer's layoutSublayers(of:) method.

   override func layoutSublayers(of layer: CALayer) {
      super.layoutSublayers(of: layer)
      gradientMaskLayer.frame = self.bounds
   }

Assuming your layer is created within a view, the view automatically assigns itself as the layer's delegate, thu sproviding the layoutSublayers(of:) method that you can then override as above. If you are not creaing it within a view then you will have to set up the delegate functionality yourself. I'd recommend doing in within a view :-)

Upvotes: 1

Related Questions