CALayer不随自动布局调整大小

20

我创建了一个渐变层来制作一个进度条,可以在tableView中使用,效果非常好。

iPhone5: enter image description here

为了让应用在多个设备上使用,我在Storyboard中创建了UIView,打上标记并添加了约束。但是,当我在iPhone 6 上使用应用程序时,CALayer 不会重新调整大小。

iPhone6: enter image description here

我觉得这太愚蠢了,但别管它了。我已经找了很久,试图理解如何解决这个问题,但没有成功。有任何人知道如何让 CALayer 随着 UIView 调整大小吗?任何帮助都将不胜感激!谢谢。

        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个回答

55

UIView 的默认层会随着其视图的大小调整,但子层不会(正如您发现的那样)。使其正常工作的一种方法是创建一个自定义视图类,将您在问题中拥有的代码移到其中,并覆盖 layoutSublayersOfLayer 方法,在其中设置渐变层与视图的大小相同。由于此代码现在位于自定义类中,我还创建了一个属性percentageCompleted(而不是局部变量),并添加了willSet子句,以便在更改 percentageCompleted 属性时任何时候都会更新该条的外观。

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
    }
}
在IB中,您需要将视图的类更改为RDProgressView(在我的示例中),并且在cellForRowAtIndexPath中,您只需要获取对该视图的引用,并设置其percentageCompleted属性。
progressBar =  cell.contentView.viewWithTag(3) as RDProgressView! 
progressBar.percentageCompleted = 0.2

非常感谢 - 它完美地运行了。你的回答很全面,解决方案优雅并且解决了我的问题。今天我将学习关于awakeFromNib和willSet。再次感谢!(哦,我缩进了第一个和最后一行第一个代码块,并通过添加let实例化了progressBar) - KML

15

作为接受答案的一种替代方法,您还可以将视图层类更改为CAGradientLayer。视图层将始终根据布局更改而调整大小。您可以通过子类化UIView来实现这一点。

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

然后设置颜色

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

相对于添加和维护子层,它的代码量更少,但可能并不适用于所有情况。


1
重写类变量 layerClass: AnyClass { 返回 CAGradientLayer.self }重写变量 layer: CAGradientLayer { 返回 super.layer as! CAGradientLayer } - lastcc
更加简洁。你能否列举出这种方法不适用的任何用例? - keeshux

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接