水平渐变不适用于动态宽度内容

时间:2018-05-30 11:49:06

标签: ios swift uiview uibutton gradient

我正在尝试根据需要为按钮或视图实现渐变。但是每当我尝试按钮/视图时,宽度是动态的(对于水平渐变),它只加载一半相同。

func applyGradient(withColours colours: [UIColor], gradientOrientation orientation: GradientOrientation) {
    let gradient: CAGradientLayer = CAGradientLayer()
    gradient.frame = self.bounds
    gradient.colors = colours.map { $0.cgColor }
    gradient.startPoint = orientation.startPoint
    gradient.endPoint = orientation.endPoint
    self.layer.insertSublayer(gradient, at: 0)
}

GradientOrientation通过以下代码获得。

enum GradientOrientation {
case topRightBottomLeft
case topLeftBottomRight
case horizontal
case vertical

var startPoint: CGPoint {
    return points.startPoint
}

var endPoint: CGPoint {
    return points.endPoint
}

var points: GradientPoints {
    switch self {
    case .topRightBottomLeft:
        return (CGPoint.init(x: 0.0, y: 1.0), CGPoint.init(x: 1.0, y: 0.0))
    case .topLeftBottomRight:
        return (CGPoint.init(x: 0.0, y: 0.0), CGPoint.init(x: 1, y: 1))
    case .horizontal:
        return (CGPoint.init(x: 0.0, y: 0.5), CGPoint.init(x: 1.0, y: 0.5))
    case .vertical:
        return (CGPoint.init(x: 0.0, y: 0.0), CGPoint.init(x: 0.0, y: 1.0))
    }
}
}

但如果宽度为150,它对于视图/按钮都会完美加载。任何帮助表示赞赏。

3 个答案:

答案 0 :(得分:1)

如果稍后应用渐变,则按钮的框架很可能不一样。您可以尝试在applyGradient中打印边界以进行检查。

无论如何你应该添加更多逻辑;因为它看起来像视图的子类,所以存储图层会很棒。目前,如果applyGradient被调用两次,您会发生什么?你很可能会有2个渐变。

所以你要添加:

private var currentGradientLayer: CAGradientLayer?
func applyGradient(withColours colours: [UIColor], gradientOrientation orientation: GradientOrientation) {
    currentGradientLayer?.removeFromSuperlayer()
    currentGradientLayer = nil

    let gradient: CAGradientLayer = {
         let gradient: CAGradientLayer = CAGradientLayer()
         gradient.frame = self.bounds
         gradient.colors = colours.map { $0.cgColor }
         gradient.startPoint = orientation.startPoint
         gradient.endPoint = orientation.endPoint
    }()

    self.layer.insertSublayer(gradient, at: 0)    
    currentGradientLayer = gradient
}

现在,既然这样做了,你应该尝试覆盖另外两种方法来修复帧:

override func layoutSubviews() {
    super.layoutSubviews()
    refreshGradientLayer()
}
override var frame: CGRect {
    didSet {
        refreshGradientLayer()
    }
}
private func refreshGradientLayer() {
    currentGradientLayer?.frame = bounds
}

这应该在任何情况下刷新渐变;当您的视图是带有约束的布局时,layoutSubviews将被调用,frame将以编程方式进行调用。

答案 1 :(得分:0)

更改超级图层时,UIView.layer中的所有子图层都不会自动更改其大小。覆盖UIView.layoutSubviews()的方法并从UIView.layer更新边界CAGradientLayer。

答案 2 :(得分:0)

<gradientlayer>.layoutIfNeeded()

计算完动态分量的宽度后,调用此方法。