在三个按钮中同时添加/删除 GradientLayer

Simultaneously Adding / Removing GradientLayer among Three Buttons

假设我有三个按钮,功能是选择按钮时,我不想为该按钮添加myGradientLayer并想要其他两个按钮。

为了添加和删除 GradientLayer,我为 UIView 创建了一个扩展,如下所示:

extension UIView {

    private var gradientLayer : CAGradientLayer {

        let gradientLayer = CAGradientLayer()
        gradientLayer.frame = self.bounds
        gradientLayer.colors = arrButtonColors.map({[=10=].cgColor})
        return gradientLayer
    }

    open func applyGradientColor() {
        self.layer.insertSublayer(gradientLayer, at: 0)
    }

    open func removeGradientLayer() {

       gradientLayer.removeFromSuperlayer() --// this does't remove gradientLayer at all

       self.layer.sublayers?.removeAll() --// this will remove all the layer include UILabelLayer , that doesn't i want

      self.layer.sublayers = nil --// same effect as above(2nd condition)

    }

}

我的功能代码在ViewController:

if view.isHidden {
            btn.applyGradientColor()
        } else  {
            btn.removeGradientLayer()
        }

我知道如果 btn(Button) 没有任何图层(不包括 UILabelLayer)那么它将 添加 GradientLayer 否则不添加,因为我试图删除所有 sublayer 首先,甚至试图删除 view.isHidden 块中 0 索引处的子层。 尽管它也不起作用。

功能代码将针对 UIButton 的不同对象执行三次

如何解决这个问题?

您已 gradientLayer 计算出 属性。这意味着您每次阅读 属性 时都会获得一个新层。改为常规 属性。

这可能意味着您必须使用 UIButton 的子类,而不是扩展。或者,让您的删除代码循环遍历所有子层,只删除渐变层。

编辑:

查找和删除渐变图层的代码可能如下所示:

open func removeGradientLayer() {
   if let layers = layer.subLayers {
     for aLayer in layers {
       if aLayer is CAGradientLayer {
         aLayer.removeFromSuperlayer
         break
       }
   }
}

您没有引用之前添加的 gradientLayer。你必须保留它。一种方法是对其进行子类化并在其中保留变量或者您也可以在运行时使用 objc_setAssociatedObject.

扩展保留它

以下是如何执行此操作的示例:

private var key = "gradientLayerKey"
extension UIView {
    private var gradientLayer: CAGradientLayer? {
        get {
            return objc_getAssociatedObject(self, &key) as? CAGradientLayer
        }

        set {
            objc_setAssociatedObject(self, &key, newValue, .OBJC_ASSOCIATION_RETAIN)
        }
    }

    private var gradientLayerInstance: CAGradientLayer {
        let newGradientLayer = CAGradientLayer()
        newGradientLayer.frame = self.bounds
        newGradientLayer.colors = arrButtonColors.map { [=10=].cgColor }
        return newGradientLayer
    }

    open func applyGradientColor() {
        gradientLayer?.removeFromSuperLayer()
        // next line sets gradientLayer and retains it.
        gradientLayer = gradientLayerInstance
        self.layer.insertSublayer(gradientLayer, at: 0)
    }

    open func removeGradientLayer() {
        gradientLayer?.removeFromSuperlayer()
    }
}