添加CAGradientLayer作为UIView子层后无法铺满视图的问题
解决CAGradientLayer无法与UIView等大的问题
这个问题我之前也碰到过!核心原因是CAGradientLayer作为子层,不会自动跟随父视图的尺寸变化——你初始化时设置的gradient.frame = cellview.bounds只是当时视图的固定尺寸,一旦视图因为AutoLayout、屏幕旋转或者其他原因调整了大小,渐变层的尺寸不会自动更新,就会出现显示不匹配的情况。
下面给你几个靠谱的解决方案,按推荐程度排序:
方案一:自定义UIView,重写layerClass(最推荐)
这种方式让视图的底层layer直接是CAGradientLayer,系统会自动帮你管理尺寸变化,完全不用手动维护frame:
class GradientView: UIView { // 告诉系统用CAGradientLayer作为当前视图的layer override class var layerClass: AnyClass { return CAGradientLayer.self } // 方便直接访问渐变层的属性 private var gradientLayer: CAGradientLayer { return layer as! CAGradientLayer } override init(frame: CGRect) { super.init(frame: frame) setupGradientConfig() } required init?(coder: NSCoder) { super.init(coder: coder) setupGradientConfig() } // 配置渐变的颜色、方向等属性 private func setupGradientConfig() { let topColor = UIColor(red: 0.435, green: 0, blue: 0.635, alpha: 1.0) let bottomColor = UIColor(red: 0.255, green: 0.043, blue: 0.373, alpha: 1.0) gradientLayer.colors = [topColor.cgColor, bottomColor.cgColor] gradientLayer.startPoint = CGPoint(x: 0, y: 0) gradientLayer.endPoint = CGPoint(x: 0.3, y: 1) gradientLayer.masksToBounds = true } }
之后初始化视图的时候直接用这个自定义类就行:
let cellview = GradientView(frame: CGRect(x: 0, y: 0, width: 192, height: 160))
方案二:自定义UIView,重写layoutSubviews
如果不想替换底层layer,也可以在自定义视图的layoutSubviews方法里更新渐变层的frame——这个方法会在视图尺寸变化时被调用:
class GradientView: UIView { private let gradient = CAGradientLayer() override init(frame: CGRect) { super.init(frame: frame) setupGradient() } required init?(coder: NSCoder) { super.init(coder: coder) setupGradient() } private func setupGradient() { let topColor = UIColor(red: 0.435, green: 0, blue: 0.635, alpha: 1.0) let bottomColor = UIColor(red: 0.255, green: 0.043, blue: 0.373, alpha: 1.0) gradient.colors = [topColor.cgColor, bottomColor.cgColor] gradient.startPoint = CGPoint(x: 0, y: 0) gradient.endPoint = CGPoint(x: 0.3, y: 1) gradient.masksToBounds = true layer.addSublayer(gradient) } // 每次视图布局更新时,重新设置渐变层的frame override func layoutSubviews() { super.layoutSubviews() gradient.frame = bounds } }
方案三:用KVO监听视图bounds变化(非自定义视图场景)
如果不能自定义视图,比如你是在ViewController里直接创建的UIView,可以用KVO监听视图的bounds变化,实时更新渐变层的尺寸:
// 初始化视图和渐变层 let cellview = UIView(frame: CGRect(x: 0, y: 0, width: 192, height: 160)) let gradient = CAGradientLayer() let topColor = UIColor(red: 0.435, green: 0, blue: 0.635, alpha: 1.0) let bottomColor = UIColor(red: 0.255, green: 0.043, blue: 0.373, alpha: 1.0) gradient.colors = [topColor.cgColor, bottomColor.cgColor] gradient.startPoint = CGPoint(x: 0, y: 0) gradient.endPoint = CGPoint(x: 0.3, y: 1) gradient.masksToBounds = true cellview.layer.addSublayer(gradient) gradient.frame = cellview.bounds // 添加KVO监听bounds变化 cellview.addObserver(self, forKeyPath: "bounds", options: [.new], context: nil)
然后在当前类里实现KVO的回调方法,记得在deinit里移除观察者:
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { if keyPath == "bounds", let view = object as? UIView { gradient.frame = view.bounds } else { super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) } } deinit { cellview.removeObserver(self, forKeyPath: "bounds") }
内容的提问来源于stack exchange,提问作者Omair
相关产品推荐
相关产品推荐

