方向转换后 UIView 的渐变
Gradient from UIView after orientation transition
我有一个 UIView 应用渐变的扩展:
extension UIView {
func applyGradient(colors: [CGColor]) {
self.backgroundColor = nil
let gradientLayer = CAGradientLayer()
gradientLayer.frame = self.bounds // Here new gradientLayer should get actual UIView bounds
gradientLayer.cornerRadius = self.layer.cornerRadius
gradientLayer.colors = colors
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.0)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 1.0)
gradientLayer.masksToBounds = true
self.layer.insertSublayer(gradientLayer, at: 0)
}
}
在我的 UIView 子类中,我正在创建我的所有视图并设置约束:
private let btnSignIn: UIButton = {
let btnSignIn = UIButton()
btnSignIn.setTitle("Sing In", for: .normal)
btnSignIn.titleLabel?.font = UIFont(name: "Avenir Medium", size: 35)
btnSignIn.layer.cornerRadius = 30
btnSignIn.clipsToBounds = true
btnSignIn.translatesAutoresizingMaskIntoConstraints = false
return btnSignIn
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubViews()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
addSubViews()
}
func addSubViews() {
self.addSubview(imageView)
self.addSubview(btnSignIn)
self.addSubview(signUpstackView)
self.addSubview(textFieldsStackView)
setConstraints()
}
我覆盖了 layoutSubviews 函数,每次更改视图边界(包括方向转换)时都会调用该函数,我正在调用 applyGradient。
override func layoutSubviews() {
super.layoutSubviews()
btnSignIn.applyGradient(colors: [Colors.ViewTopGradient, Colors.ViewBottomGradient])
}
问题是方向过渡渐变由于某种原因应用错误后...
请看截图
我在这里错过了什么?
如果你看一下你的按钮,你会看到两个渐变。那是因为 layoutSubviews
至少被调用了两次,第一次是在第一次呈现视图时,第二次是在方向改变之后。所以你至少添加了两个渐变层。
你想改变这个所以你只 insertSublayer
一次(例如,当视图被实例化时),并且因为 layoutSubviews
可以被调用多次,它应该限制自己只调整现有的层,不添加任何层。
你也可以只用layerClass
class 属性 把按钮的主图层做成渐变,这样就完全不用手动调整图层边框了:
@IBDesignable
public class RoundedGradientButton: UIButton {
static public override var layerClass: AnyClass { CAGradientLayer.self }
private var gradientLayer: CAGradientLayer { layer as! CAGradientLayer }
@IBInspectable var startColor: UIColor = .blue { didSet { updateColors() } }
@IBInspectable var endColor: UIColor = .red { didSet { updateColors() } }
override public init(frame: CGRect = .zero) {
super.init(frame: frame)
configure()
}
required public init?(coder: NSCoder) {
super.init(coder: coder)
configure()
}
override public func layoutSubviews() {
super.layoutSubviews()
layer.cornerRadius = min(bounds.height, bounds.width) / 2
}
}
private extension RoundedGradientButton {
func configure() {
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = CGPoint(x: 1, y: 1)
updateColors()
titleLabel?.font = UIFont(name: "Avenir Medium", size: 35)
}
func updateColors() {
gradientLayer.colors = [startColor.cgColor, endColor.cgColor]
}
}
此技术消除了手动调整层的 frame
的需要,并且还产生了更好的中间动画再现。
我有一个 UIView 应用渐变的扩展:
extension UIView {
func applyGradient(colors: [CGColor]) {
self.backgroundColor = nil
let gradientLayer = CAGradientLayer()
gradientLayer.frame = self.bounds // Here new gradientLayer should get actual UIView bounds
gradientLayer.cornerRadius = self.layer.cornerRadius
gradientLayer.colors = colors
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.0)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 1.0)
gradientLayer.masksToBounds = true
self.layer.insertSublayer(gradientLayer, at: 0)
}
}
在我的 UIView 子类中,我正在创建我的所有视图并设置约束:
private let btnSignIn: UIButton = {
let btnSignIn = UIButton()
btnSignIn.setTitle("Sing In", for: .normal)
btnSignIn.titleLabel?.font = UIFont(name: "Avenir Medium", size: 35)
btnSignIn.layer.cornerRadius = 30
btnSignIn.clipsToBounds = true
btnSignIn.translatesAutoresizingMaskIntoConstraints = false
return btnSignIn
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubViews()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
addSubViews()
}
func addSubViews() {
self.addSubview(imageView)
self.addSubview(btnSignIn)
self.addSubview(signUpstackView)
self.addSubview(textFieldsStackView)
setConstraints()
}
我覆盖了 layoutSubviews 函数,每次更改视图边界(包括方向转换)时都会调用该函数,我正在调用 applyGradient。
override func layoutSubviews() {
super.layoutSubviews()
btnSignIn.applyGradient(colors: [Colors.ViewTopGradient, Colors.ViewBottomGradient])
}
问题是方向过渡渐变由于某种原因应用错误后...
请看截图
我在这里错过了什么?
如果你看一下你的按钮,你会看到两个渐变。那是因为 layoutSubviews
至少被调用了两次,第一次是在第一次呈现视图时,第二次是在方向改变之后。所以你至少添加了两个渐变层。
你想改变这个所以你只 insertSublayer
一次(例如,当视图被实例化时),并且因为 layoutSubviews
可以被调用多次,它应该限制自己只调整现有的层,不添加任何层。
你也可以只用layerClass
class 属性 把按钮的主图层做成渐变,这样就完全不用手动调整图层边框了:
@IBDesignable
public class RoundedGradientButton: UIButton {
static public override var layerClass: AnyClass { CAGradientLayer.self }
private var gradientLayer: CAGradientLayer { layer as! CAGradientLayer }
@IBInspectable var startColor: UIColor = .blue { didSet { updateColors() } }
@IBInspectable var endColor: UIColor = .red { didSet { updateColors() } }
override public init(frame: CGRect = .zero) {
super.init(frame: frame)
configure()
}
required public init?(coder: NSCoder) {
super.init(coder: coder)
configure()
}
override public func layoutSubviews() {
super.layoutSubviews()
layer.cornerRadius = min(bounds.height, bounds.width) / 2
}
}
private extension RoundedGradientButton {
func configure() {
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = CGPoint(x: 1, y: 1)
updateColors()
titleLabel?.font = UIFont(name: "Avenir Medium", size: 35)
}
func updateColors() {
gradientLayer.colors = [startColor.cgColor, endColor.cgColor]
}
}
此技术消除了手动调整层的 frame
的需要,并且还产生了更好的中间动画再现。