我有一段时间写了这个自定义代码,以便在我的视图上有一个渐变边框。唯一的问题是,它已经慢慢成为我的应用程序中最严重的崩溃问题。
我在 crashlytics 中收到的崩溃日志指向
super.layoutSubviews()
行,这对我来说没有多大意义。
有人对改进有任何想法,或者有不同的方法来做同样的事情,可以减少崩溃吗?我从这个视图中每周获得 120-200。
class GradientBorderView: UIView {
var enableGradientBorder: Bool = false
var borderGradientColors: [UIColor] = [] {
didSet {
setNeedsLayout()
}
}
override func layoutSubviews() {
super.layoutSubviews()
guard enableGradientBorder && !borderGradientColors.isEmpty else {
layer.borderColor = nil
return
}
let gradient = UIImage.imageGradient(bounds: bounds, colors: borderGradientColors)
layer.borderColor = UIColor(patternImage: gradient).cgColor
}
}
extension UIImage {
static func imageGradient(bounds: CGRect, colors: [UIColor]) -> UIImage {
let gradientLayer = CAGradientLayer()
gradientLayer.frame = bounds
gradientLayer.colors = colors.map(\.cgColor)
// This makes it left to right, default is top to bottom
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
let renderer = UIGraphicsImageRenderer(bounds: bounds)
return renderer.image { gradientLayer.render(in: $0.cgContext) }
}
}
很难说为什么你会崩溃,除非你可以提供重现它的代码。
但是,您可能会发现将
CAGradientLayer
与 .mask
结合使用是更好、更高效的选择:
class MyGradientBorderView: UIView {
var enableGradientBorder: Bool = false { didSet { setNeedsLayout() } }
var borderGradientColors: [UIColor] = [] { didSet { setNeedsLayout() } }
var gradientBorderWidth: CGFloat = 8.0 { didSet { setNeedsLayout() } }
let gLayer: CAGradientLayer = CAGradientLayer()
let mskLayer: CAShapeLayer = CAShapeLayer()
override func layoutSubviews() {
super.layoutSubviews()
guard enableGradientBorder, gradientBorderWidth > 0.0, !borderGradientColors.isEmpty else {
gLayer.removeFromSuperlayer()
return
}
if gLayer.superlayer == nil {
layer.addSublayer(gLayer)
}
gLayer.frame = bounds
gLayer.colors = borderGradientColors.map(\.cgColor)
gLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
gLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
let w: CGFloat = gradientBorderWidth
mskLayer.path = UIBezierPath(rect: bounds.insetBy(dx: w * 0.5, dy: w * 0.5)).cgPath
mskLayer.fillColor = UIColor.clear.cgColor
mskLayer.strokeColor = UIColor.red.cgColor // any opaque color
mskLayer.lineWidth = w
gLayer.mask = mskLayer
}
}