首页 > 解决方案 > 为什么 UIButton 不显示渐变

问题描述

嗨,我是 Swift 和 Xcode 的新手,只是学习基础知识。我以编程方式添加了一个渐变层,然后UIButton使用主故事板添加了一个并为其分配了一个出口,但是当我运行代码时,渐变层显示但按钮显示,但是,当我删除渐变层时,UIButton显示。附件是同时使用渐变和代码时发生的情况的屏幕截图,并且将附加 a。

class ViewController: UIViewController {
    let layer = CAGradientLayer()

    @IBOutlet weak var pressMeButton: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        layer.frame = view.bounds
        layer.colors = [UIColor.white.cgColor, UIColor(red: 128/255, green: 206/255, blue: 255/255, alpha: 1).cgColor]
        layer.startPoint = CGPoint(x: 0, y: 0)
        layer.endPoint = CGPoint(x: 0, y: 0.4)
        view.layer.addSublayer(layer)

        pressMeButton.layer.cornerRadius = 25.0
        pressMeButton.layer.borderWidth = 0.8
        pressMeButton.layer.borderColor = UIColor.black.cgColor
        pressMeButton.setTitle("Press Me", for: .normal)
        pressMeButton.setTitleColor(.black, for: .normal)
    }
}

带有故事板的代码显示按钮放置和没有按钮的模拟器:

屏幕快照

标签: iosswiftxcodestoryboardios-simulator

解决方案


主要问题是渐变层放置在按钮的顶部。第二个问题(你还没有提到)是如果你旋转设备,它不会响应框架中的变化。

最好的解决方案是定义一个GradientView由它决定的支持层layerClass是一个CAGradientLayer。这样(a)它将始终位于按钮下方;并且 (b) 它会自动适应变化(并且在动画期间也会比或接近时frame更优雅地这样做):layoutSubviewsviewDidLayoutSubviews

@IBDesignable
class GradientView: UIView {
    override class var layerClass: AnyClass { return CAGradientLayer.self }
    private var gradientLayer: CAGradientLayer { return layer as! CAGradientLayer }

    @IBInspectable var startColor: UIColor = .white { didSet { updateGradient() } }
    @IBInspectable var endColor:   UIColor = #colorLiteral(red: 0.5019607843, green: 0.8078431373, blue: 1, alpha: 1)     { didSet { updateGradient() } }
    @IBInspectable var startPoint: CGFloat = 0      { didSet { updateGradient() } }
    @IBInspectable var endPoint:   CGFloat = 0.4    { didSet { updateGradient() } }


    override init(frame: CGRect = .zero) {
        super.init(frame: frame)
        updateGradient()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        updateGradient()
    }
}

private extension GradientView {
    func updateGradient() {
        gradientLayer.colors = [startColor, endColor].map { $0.cgColor }
        gradientLayer.startPoint = CGPoint(x: 0, y: startPoint)
        gradientLayer.endPoint = CGPoint(x: 0, y: endPoint)
    }
}

使用这个@IBDesignable类,您可以将视图控制器的视图的基类设置为GradientView,它将呈现在按钮下方,并正确显示在 Interface Builder 中。例如,单击背景视图并转到最右侧面板中的“Identity Inspector”选项卡,并在“Custom Class”部分设置“Class”:

在此处输入图像描述

如果需要,您可以在 IB 中更改开始/结束颜色和开始/结束点,方法是选择右侧的“属性检查器”面板:

在此处输入图像描述

显然,如果您这样做,那么您根本不必在视图层中玩耍viewDidLoad。但是,如果您想以编程方式更改它,您可以执行以下操作:

override func viewDidLoad() {
    super.viewDidLoad()

    if let view = view as? GradientView {
        view.startColor = .black
        view.endColor = .red
    }
}

但我个人会在 IB 中正确设置颜色(或其他)。而且我会将所有“视图配置”代码保留UIView在它所属的类中,而不是在视图控制器中。


推荐阅读