Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 同时在三个按钮之间添加/删除GradientLayer_Ios_Swift_Cagradientlayer - Fatal编程技术网

Ios 同时在三个按钮之间添加/删除GradientLayer

Ios 同时在三个按钮之间添加/删除GradientLayer,ios,swift,cagradientlayer,Ios,Swift,Cagradientlayer,假设我有三个按钮,其功能是当选择按钮时,我不想为该按钮添加MygradientLayer,而想为其他两个按钮添加MygradientLayer 为了添加和删除GradientLayer,我为UIView创建了一个扩展,如下所示: extension UIView { private var gradientLayer : CAGradientLayer { let gradientLayer = CAGradientLayer() gradientLa

假设我有三个按钮,其功能是当选择按钮时,我不想为该按钮添加MygradientLayer,而想为其他两个按钮添加MygradientLayer

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

extension UIView {

    private var gradientLayer : CAGradientLayer {

        let gradientLayer = CAGradientLayer()
        gradientLayer.frame = self.bounds
        gradientLayer.colors = arrButtonColors.map({$0.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中的功能代码:

我知道,如果btn(按钮)没有任何层(不包括UILabelLayer),那么它会 添加GradientLayer,否则不行,因为我试图删除所有 首先是子层,甚至尝试在view.ishiden块中删除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\u 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 { $0.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()
    }
}

嘿,Duncan首先感谢您的回复,但是有没有其他方法来创建UIButton的子类呢?为什么不使用扩展?您不能在扩展中创建存储的属性,并且您需要某种方法到达渐变层以删除它。如果您将UIButton子类化,则可以使用一个存储属性来删除它。另一种选择,如我所提到的,是通过子层循环并移除你找到的第一个渐变层。是的,我知道我们不能在扩展中创建存储属性,这就是为什么我创建了私有计算属性,但没关系,邓肯,我试过你的代码,它的工作,但只针对三个按钮中的第二个按钮。。!这意味着它只为第二个按钮找到了一个CAGradientLayer。我尝试了这个:self.layer.sublayers?.forEach({$0.removeFromSuperlayer()}),但这将删除UILabelLayerOk,你需要调试你的代码,找出为什么其他按钮找不到渐变层。
sublayers?.forEach()
代码将始终删除每一层,因此它与您原来的
sublayers?.removeAll()
code.nice farzadshbfn没有什么不同。我尝试了您的代码及其工作,很高兴今天知道了像objc_setAssociatedObject这样的新概念。谢谢,但是如果要找到我们刚刚插入的gradientLayer,我要说的是按照Duncan C的建议,比如removeGradientLayer()方法中的for循环,对代码进行少量剪切。那么为什么不将
gradientLayer
设置为public?我将其设置为private,以遵循您的代码,但是如果你不将它标记为私有,你可以从任何地方访问它。或者我不太明白你的问题:D@farzadshbfn,使用自定义getter/setter和关联对象来模拟存储属性,这是另一个选项。您不能将存储的属性添加到扩展中(除非您使用与您的答案类似的关联对象。)@duncan这是在扩展中半存储属性的唯一方法。而且它只适用于类。有时它们会派上用场,特别是在使用库时。
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 { $0.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()
    }
}