CALayer not resizing with Autolayout

I have created a progress bar to be used in a tableView by creating a gradient layer. It works perfectly.

iPhone5:
enter image description here

  • How To Properly Compress UIImages At Runtime
  • New Fixed position bug on iOS8
  • Monitoring a directory in Cocoa/Cocoa Touch
  • “self” not available in debugger on iOS 5.1
  • GKMatchmaker findMatchForRequest invite never received
  • Use Xcode 8 with iOS 11
  • In order to use the app on multiple devices, I have created the UIView in Storyboard, tagged it and added constraints.
    However, when I use the app on an iPhone 6 the CALayer don’t resize.

    iPhone6:
    enter image description here

    I find this extremely stupid, but never mind. I have looked around and tried to understand how to solve this for months, but I have come up short. Does ANYONE know how to make CALayers resize with the UIView? Any help would be very much appreciated ! Thank you.

            progressBar =  cell.contentView.viewWithTag(3) as UIView!
            progressBar.layer.cornerRadius = 4
            progressBar.layer.masksToBounds = true
    
    
            // create gradient layer
            let gradient : CAGradientLayer = CAGradientLayer()
    
            // create color array
            let arrayColors: [AnyObject] = [
                UIColor (red: 255/255, green: 138/255, blue: 1/255, alpha: 1).CGColor,
                UIColor (red: 110/255, green: 110/255, blue: 118/255, alpha: 1).CGColor]
    
            // set gradient frame bounds to match progressBar bounds
            gradient.frame = progressBar.bounds
    
            // set gradient's color array
            gradient.colors = arrayColors
    
            //Set progress(progressBar)
            var percentageCompleted = 0.6
    
            gradient.startPoint = CGPoint(x: 0.0, y: 0.5)
            gradient.locations = [percentageCompleted, percentageCompleted]
            gradient.endPoint = CGPoint(x: 1, y: 0.5)
    
            // replace base layer with gradient layer
            progressBar.layer.insertSublayer(gradient, atIndex: 0)
    

    2 Solutions Collect From Internet About “CALayer not resizing with Autolayout”

    The default layer of a UIView does resize with its view, but sublayers don’t (as you found out). One way to make this work is to create a custom view class, move the code you have in your question to it, and override layoutSublayersOfLayer where you can set the gradient layer to be the same size as the view. Because this code is now in a custom class, I also created a property percentageCompleted (instead of a local variable), and added a willSet clause so the bar’s appearance is updated any time you change the percentageCompleted property.

    class RDProgressView: UIView {
    
        private let gradient : CAGradientLayer = CAGradientLayer()
    
        var percentageCompleted: Double = 0.0 {
            willSet{
                gradient.locations = [newValue, newValue]
            }
        }
    
        override func awakeFromNib() {
            self.layer.cornerRadius = 4
            self.layer.masksToBounds = true
    
            // create color array
            let arrayColors: [AnyObject] = [
                UIColor (red: 255/255, green: 138/255, blue: 1/255, alpha: 1).CGColor,
                UIColor (red: 110/255, green: 110/255, blue: 118/255, alpha: 1).CGColor]
    
            // set gradient's color array
            gradient.colors = arrayColors
    
            //Set progress(progressBar)
            gradient.startPoint = CGPoint(x: 0.0, y: 0.5)
            gradient.locations = [percentageCompleted, percentageCompleted]
            gradient.endPoint = CGPoint(x: 1, y: 0.5)
    
            self.layer.insertSublayer(gradient, atIndex: 0)
        }
    
        override func layoutSublayersOfLayer(layer: CALayer!) {
            super.layoutSublayersOfLayer(layer)
            gradient.frame = self.bounds
        }
    }
    

    In IB, you would change the class of your view to RDProgressView (in my example), and in cellForRowAtIndexPath, you would only need to get a reference to the view, and set its percentageCompleted property.

    progressBar =  cell.contentView.viewWithTag(3) as RDProgressView! 
    progressBar.percentageCompleted = 0.2
    

    As an alternative to the accepted answer, you could also change the views layer class to be CAGradientLayer. The views layer will always be resized according to layout changes. You can achieve that by subclassing UIView

    class GradientView: UIView {
      override class func layerClass() -> AnyClass {
        return CAGradientLayer.self
      }
    }
    

    then set the colors

    if let gradientLayer = gradientView.layer as? CAGradientLayer {
      gradientLayer.colors = arrayColors
    }
    

    It’s less code than adding and maintaining a sublayer, but might not suit all use cases.