可以将 UIButton 图像设置为零索引吗?
Possible to set UIButton image to be at zero index?
我为 UIButton 创建了一个子class,我在其中绘制了一个 CAShapelayer 作为按钮的圆形背景色,效果很好。然而,CAShapeLayer 现在覆盖了按钮图像。
处理此问题的最佳方法是什么?我试过插入 CAShapeLayer 但没有任何效果。有没有办法将按钮图像置于前台?
这就是我目前投射按钮图片的方式:
var buttonImage: UIImage = UIImage(named: "icon_check")! {
didSet {
setImage(buttonImage, for: .normal)
}
}
更新:整个class的代码:
class PulseButton: UIButton {
let buttonFillLayer = CAShapeLayer()
let pulsatingLayer = CAShapeLayer()
var buttonFillLayerFillColor: UIColor = .buttonLayerFillColor { didSet { buttonFillLayer.fillColor = buttonFillLayerFillColor.cgColor } }
var pulsatingLayerFillColor: UIColor = .pulsatingLayerFillColor { didSet { pulsatingLayer.fillColor = pulsatingLayerFillColor.cgColor } }
var buttonFillLayerStrokeStart: CGFloat = 0 { didSet { buttonFillLayer.strokeStart = buttonFillLayerStrokeStart } }
var pulsatingLayerStrokeStart: CGFloat = 0 { didSet { pulsatingLayer.strokeStart = pulsatingLayerStrokeStart } }
var buttonFillLayerStrokeEnd: CGFloat = 1 { didSet { buttonFillLayer.strokeEnd = buttonFillLayerStrokeEnd } }
var pulsatingLayerStrokeEnd: CGFloat = 1 { didSet { pulsatingLayer.strokeEnd = pulsatingLayerStrokeEnd } }
var buttonImage: UIImage = UIImage(named: "icon_check")! {
didSet {
setImage(buttonImage, for: .normal)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupLayout()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupLayout()
}
override func layoutSubviews() {
super.layoutSubviews()
updatePaths()
}
private func setupLayout() {
pulsatingLayer.strokeColor = UIColor.clear.cgColor
pulsatingLayer.fillColor = buttonFillLayerFillColor.cgColor
pulsatingLayer.strokeStart = buttonFillLayerStrokeStart
pulsatingLayer.strokeEnd = buttonFillLayerStrokeEnd
buttonFillLayer.strokeColor = UIColor.clear.cgColor
buttonFillLayer.fillColor = pulsatingLayerFillColor.cgColor
buttonFillLayer.strokeStart = pulsatingLayerStrokeStart
buttonFillLayer.strokeEnd = pulsatingLayerStrokeEnd
layer.addSublayer(pulsatingLayer)
layer.addSublayer(buttonFillLayer)
}
private func updatePaths() {
print("Updating")
//Parameters for layers
let arcCenter = CGPoint(x: bounds.midX, y: bounds.midY)
let radius = (min(bounds.width, bounds.height)) / 2
let path = UIBezierPath(arcCenter: arcCenter, radius: radius, startAngle: 0, endAngle: 2*CGFloat.pi, clockwise: true).cgPath
pulsatingLayer.transform = CATransform3DIdentity
pulsatingLayer.frame = bounds
pulsatingLayer.transform = CATransform3DMakeRotation(-CGFloat.pi/2, 0, 0, 1)
buttonFillLayer.transform = CATransform3DIdentity
buttonFillLayer.frame = bounds
buttonFillLayer.transform = CATransform3DMakeRotation(-CGFloat.pi/2, 0, 0, 1)
pulsatingLayer.path = path
buttonFillLayer.path = path
}
func animateCircle() {
let scaleUpAimation = CABasicAnimation(keyPath: "transform.scale")
scaleUpAimation.fromValue = 1
scaleUpAimation.toValue = 1.4
scaleUpAimation.duration = 0.8
scaleUpAimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
self.pulsatingLayer.add(scaleUpAimation, forKey: "pulsing")
let opacityAnimation = CABasicAnimation(keyPath: "opacity")
opacityAnimation.fromValue = 0.6
opacityAnimation.toValue = 0
opacityAnimation.duration = 0.8
opacityAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
pulsatingLayer.add(opacityAnimation, forKey: "changing opacity")
}
}
我创建了一个简单示例,用于将 CAShapeLayer
和 UIImage 添加到 UIButton。
1. UIButton
的扩展
extension UIButton
{
func addLayer()
{
let layer = CAShapeLayer()
layer.path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: 100, height: 100), cornerRadius: 50).cgPath
layer.fillColor = UIColor.red.cgColor
self.layer.insertSublayer(layer, at: 0)
}
}
2。将 CAShapeLayer
添加到 UIButton
在viewWillLayoutSubviews()
中添加CAShapeLayer
。
class ViewController: UIViewController
{
@IBOutlet weak var button: UIButton!
var layerAdded = false
override func viewDidLoad()
{
super.viewDidLoad()
self.button.setImage(#imageLiteral(resourceName: "furnish_exhaust"), for: .normal)
}
override func viewWillLayoutSubviews()
{
super.viewWillLayoutSubviews()
if !self.layerAdded
{
self.layerAdded = true
self.button.addLayer()
}
}
}
你有两个问题:
您实际上并没有设置按钮的图像。您尝试为 buttonImage
创建一个 didSet
观察者,但该观察者不会在初始化时被调用。如果 buttonImage
被重新分配,它只会在以后被调用。解决此问题的一种方法是在 setupLayout()
中将其设置为自身,如下所示:
private func setupLayout() {
buttonImage = { buttonImage }()
请注意,Swift 不会让您将 属性 分配给它自己,因此我使用匿名闭包来获取当前的 buttonImage
值。
如果要确保您的层位于其他层之下,则需要在添加自己的层之前让按钮执行其正常布局。所以不要在setupLayout
中添加图层。等到 layoutSubviews
插入图层:
override func layoutSubviews() {
super.layoutSubviews()
if pulsatingLayer.superlayer == nil {
layer.insertSublayer(pulsatingLayer, at: 0)
layer.insertSublayer(buttonFillLayer, at: 1)
}
updatePaths()
}
结果:
我为 UIButton 创建了一个子class,我在其中绘制了一个 CAShapelayer 作为按钮的圆形背景色,效果很好。然而,CAShapeLayer 现在覆盖了按钮图像。
处理此问题的最佳方法是什么?我试过插入 CAShapeLayer 但没有任何效果。有没有办法将按钮图像置于前台?
这就是我目前投射按钮图片的方式:
var buttonImage: UIImage = UIImage(named: "icon_check")! {
didSet {
setImage(buttonImage, for: .normal)
}
}
更新:整个class的代码:
class PulseButton: UIButton {
let buttonFillLayer = CAShapeLayer()
let pulsatingLayer = CAShapeLayer()
var buttonFillLayerFillColor: UIColor = .buttonLayerFillColor { didSet { buttonFillLayer.fillColor = buttonFillLayerFillColor.cgColor } }
var pulsatingLayerFillColor: UIColor = .pulsatingLayerFillColor { didSet { pulsatingLayer.fillColor = pulsatingLayerFillColor.cgColor } }
var buttonFillLayerStrokeStart: CGFloat = 0 { didSet { buttonFillLayer.strokeStart = buttonFillLayerStrokeStart } }
var pulsatingLayerStrokeStart: CGFloat = 0 { didSet { pulsatingLayer.strokeStart = pulsatingLayerStrokeStart } }
var buttonFillLayerStrokeEnd: CGFloat = 1 { didSet { buttonFillLayer.strokeEnd = buttonFillLayerStrokeEnd } }
var pulsatingLayerStrokeEnd: CGFloat = 1 { didSet { pulsatingLayer.strokeEnd = pulsatingLayerStrokeEnd } }
var buttonImage: UIImage = UIImage(named: "icon_check")! {
didSet {
setImage(buttonImage, for: .normal)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupLayout()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupLayout()
}
override func layoutSubviews() {
super.layoutSubviews()
updatePaths()
}
private func setupLayout() {
pulsatingLayer.strokeColor = UIColor.clear.cgColor
pulsatingLayer.fillColor = buttonFillLayerFillColor.cgColor
pulsatingLayer.strokeStart = buttonFillLayerStrokeStart
pulsatingLayer.strokeEnd = buttonFillLayerStrokeEnd
buttonFillLayer.strokeColor = UIColor.clear.cgColor
buttonFillLayer.fillColor = pulsatingLayerFillColor.cgColor
buttonFillLayer.strokeStart = pulsatingLayerStrokeStart
buttonFillLayer.strokeEnd = pulsatingLayerStrokeEnd
layer.addSublayer(pulsatingLayer)
layer.addSublayer(buttonFillLayer)
}
private func updatePaths() {
print("Updating")
//Parameters for layers
let arcCenter = CGPoint(x: bounds.midX, y: bounds.midY)
let radius = (min(bounds.width, bounds.height)) / 2
let path = UIBezierPath(arcCenter: arcCenter, radius: radius, startAngle: 0, endAngle: 2*CGFloat.pi, clockwise: true).cgPath
pulsatingLayer.transform = CATransform3DIdentity
pulsatingLayer.frame = bounds
pulsatingLayer.transform = CATransform3DMakeRotation(-CGFloat.pi/2, 0, 0, 1)
buttonFillLayer.transform = CATransform3DIdentity
buttonFillLayer.frame = bounds
buttonFillLayer.transform = CATransform3DMakeRotation(-CGFloat.pi/2, 0, 0, 1)
pulsatingLayer.path = path
buttonFillLayer.path = path
}
func animateCircle() {
let scaleUpAimation = CABasicAnimation(keyPath: "transform.scale")
scaleUpAimation.fromValue = 1
scaleUpAimation.toValue = 1.4
scaleUpAimation.duration = 0.8
scaleUpAimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
self.pulsatingLayer.add(scaleUpAimation, forKey: "pulsing")
let opacityAnimation = CABasicAnimation(keyPath: "opacity")
opacityAnimation.fromValue = 0.6
opacityAnimation.toValue = 0
opacityAnimation.duration = 0.8
opacityAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
pulsatingLayer.add(opacityAnimation, forKey: "changing opacity")
}
}
我创建了一个简单示例,用于将 CAShapeLayer
和 UIImage 添加到 UIButton。
1. UIButton
extension UIButton
{
func addLayer()
{
let layer = CAShapeLayer()
layer.path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: 100, height: 100), cornerRadius: 50).cgPath
layer.fillColor = UIColor.red.cgColor
self.layer.insertSublayer(layer, at: 0)
}
}
2。将 CAShapeLayer
添加到 UIButton
在viewWillLayoutSubviews()
中添加CAShapeLayer
。
class ViewController: UIViewController
{
@IBOutlet weak var button: UIButton!
var layerAdded = false
override func viewDidLoad()
{
super.viewDidLoad()
self.button.setImage(#imageLiteral(resourceName: "furnish_exhaust"), for: .normal)
}
override func viewWillLayoutSubviews()
{
super.viewWillLayoutSubviews()
if !self.layerAdded
{
self.layerAdded = true
self.button.addLayer()
}
}
}
你有两个问题:
您实际上并没有设置按钮的图像。您尝试为
buttonImage
创建一个didSet
观察者,但该观察者不会在初始化时被调用。如果buttonImage
被重新分配,它只会在以后被调用。解决此问题的一种方法是在setupLayout()
中将其设置为自身,如下所示:private func setupLayout() { buttonImage = { buttonImage }()
请注意,Swift 不会让您将 属性 分配给它自己,因此我使用匿名闭包来获取当前的
buttonImage
值。如果要确保您的层位于其他层之下,则需要在添加自己的层之前让按钮执行其正常布局。所以不要在
setupLayout
中添加图层。等到layoutSubviews
插入图层:override func layoutSubviews() { super.layoutSubviews() if pulsatingLayer.superlayer == nil { layer.insertSublayer(pulsatingLayer, at: 0) layer.insertSublayer(buttonFillLayer, at: 1) } updatePaths() }
结果: