【问题标题】:Gradient Button Crashed when Removing Gradient移除渐变时渐变按钮崩溃
【发布时间】:2020-09-17 06:31:40
【问题描述】:

所以我是学习 Swift 的新手,我在删除按钮渐变背景时遇到了麻烦,从技术上讲,我可以“删除”它,但它不稳定,如果多次点击它会崩溃。我猜这与没有“安全”删除子层有关,但我环顾四周,就是想不通。

@IBAction func button(_ sender: UIButton) {
    sender.setTitleColor(.systemBackground, for: .selected)
    sender.isSelected = !sender.isSelected
    if sender.isSelected {
        sender.layer.borderWidth = 0
        sender.applyGradient(colors: [ #colorLiteral(red: 0.5098039216, green: 0.8431372549, blue: 0.5254901961, alpha: 1) , #colorLiteral(red: 0.3058823529, green: 0.6941176471, blue: 0.3215686275, alpha: 1) ], radius: 10)
    } else {
        sender.layer.borderWidth = 1
        sender.layer.sublayers!.remove(at: 1)   // this not stable, cause crash if trigger repeatedly
    }
}

extension UIButton {
    func applyGradient(colors: [CGColor], radius: CGFloat = 0, startGradient: CGPoint = CGPoint(x: 0.5, y: 0.0), endGradient: CGPoint = CGPoint(x: 0.5, y: 1.0)) {
        let gradientLayer = CAGradientLayer()
        gradientLayer.cornerRadius = radius
        gradientLayer.colors = colors
        gradientLayer.startPoint = startGradient
        gradientLayer.endPoint = endGradient
        gradientLayer.frame = self.bounds
        self.layer.insertSublayer(gradientLayer, at: 0)
    }
}

【问题讨论】:

    标签: ios swift uibutton uikit cagradientlayer


    【解决方案1】:

    你可以给你的CALayer一个名字,这样你就可以在删除它之前找到你的层的索引:

    extension UIButton {
        func applyGradient(colors: [CGColor], radius: CGFloat = 0, startGradient: CGPoint = .init(x: 0.5, y: 0), endGradient: CGPoint = .init(x: 0.5, y: 1)) {
            // check first if there is already a gradient layer to avoid adding more than one
            if let gradientLayer = layer.sublayers?.first(where: {$0.name == "gradient" }) as? CAGradientLayer {
                gradientLayer.cornerRadius = radius
                gradientLayer.colors = colors
                gradientLayer.startPoint = startGradient
                gradientLayer.endPoint = endGradient
                gradientLayer.frame = bounds
            // if not found create a new gradient layer
            } else {
                let gradientLayer = CAGradientLayer()
                gradientLayer.name = "gradient"
                gradientLayer.cornerRadius = radius
                gradientLayer.colors = colors
                gradientLayer.startPoint = startGradient
                gradientLayer.endPoint = endGradient
                gradientLayer.frame = bounds
                layer.insertSublayer(gradientLayer, at: 0)
            }
        }
    }
    

    @IBAction func button(_ sender: UIButton) {
        sender.setTitleColor(.systemBackground, for: .selected)
        sender.isSelected.toggle()
        if sender.isSelected {
            sender.layer.borderWidth = 0
            sender.applyGradient(colors: [ #colorLiteral(red: 0.5098039216, green: 0.8431372549, blue: 0.5254901961, alpha: 1) , #colorLiteral(red: 0.3058823529, green: 0.6941176471, blue: 0.3215686275, alpha: 1) ], radius: 10)
        } else {
            sender.layer.borderWidth = 1
            if let firstIndex = sender.layer.sublayers?.firstIndex(where: {$0.name == "gradient" }) {
                sender.layer.sublayers?.remove(at: firstIndex)
            }
        }
    }
    

    【讨论】:

    • 哇,这可能是需要的最长和最多的更改,但它确实有效!我再也不能让它崩溃了!你是救生员!费尽心思想弄清楚并寻找解决方案,这绝对比我目前的水平要先进得多。看来,命名层并删除所述层是最安全的方法,我在这里看到了许多新技术和代码要学习。非常感谢!
    【解决方案2】:

    它崩溃了,因为您试图强行删除不存在的东西,检查它是否存在,然后尝试删除它。方法如下:

    @IBAction func button(_ sender: UIButton) {
        sender.setTitleColor(.systemBackground, for: .selected)
    
        sender.isSelected = !sender.isSelected
        if sender.isSelected {
            sender.layer.borderWidth = 0
            sender.applyGradient(colors: [ #colorLiteral(red: 0.5098039216, green: 0.8431372549, blue: 0.5254901961, alpha: 1) , #colorLiteral(red: 0.3058823529, green: 0.6941176471, blue: 0.3215686275, alpha: 1) ], radius: 10)
        } else {
            sender.layer.borderWidth = 1
            if sender.layer.sublayers?.count > 1 {
                sender.layer.sublayers?.remove(at: 1)
            }
        }
    }
    

    【讨论】:

    • 谢谢,但这给了我一个Thread 1: EXC_BAD_ACCESS (code=1, address=0x32f366b27ab8)
    • 不知何故你不能sender.layer.sublayers?.count,Xcode 给出了这个Value of optional type 'Int?' must be unwrapped to a value of type 'Int',把它变成let sublayers=sender.layer.sublayers, sublayers.count > 1 似乎让它沉默了
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-22
    • 2012-08-26
    • 1970-01-01
    相关资源
    最近更新 更多