今天在做项目的时候偶然需要一个“渐变色”按钮,查阅了许多资料,走了一些弯路,不过好在最终是达成效果了。
下面主要讲解两种常用解决方案,针对iOS和macOS,可以分开对应使用。
draw(_ dirtyRect:)
该方案macOS和iOS通用,且macOS推荐使用此方法。
下面以macOS (Big Sur 11.4) 为例:
1 2 3
|
class GradientButton: NSButton {}
|
加入如下属性
1 2 3 4 5 6
| class GradientButton: NSButton { var needsGradientBackground: Bool = false var startColor: NSColor? var endColor: NSColor? var gradientAngle: CGFloat = 0 }
|
对NSButton的draw(_ dirtyRect:)进行override
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| override func draw(_ dirtyRect: NSRect) { if needsGradientBackground, let startColor = startColor, let endColor = endColor { let gradient = NSGradient(starting: startColor, ending: endColor) let gradient2 = NSGradient(colors: [startColor, endColor, NSColor.systemPink])
gradient?.draw(in: bounds, angle: gradientAngle) } super.draw(dirtyRect) }
|
最后实例化一个button
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class ViewController: NSViewController { var gradientBtn: GradientButton!
override func viewDidLoad() { super.viewDidLoad() gradientBtn = .init(frame: NSMakeRect(50, 50, 200, 50)) gradientBtn.isBordered = false gradientBtn.startColor = NSColor.orange gradientBtn.endColor = NSColor.systemPink gradientBtn.needsGradientBackground = true gradientBtn.wantsLayer = true gradientBtn.layer?.cornerRadius = 24 gradientBtn.title = "Gradient" gradientBtn.attributedTitle = NSAttributedString(string: "Gradient", attributes: [.foregroundColor: NSColor.systemBlue]) view.addSubview(gradientBtn) } }
|
大功告成!
CAGradientLayer
该方法不推荐macOS使用(至少从我的测试结果来看,为NSButton添加一层layer,会直接覆盖掉title,导致无法显示按钮文字。如果有解决办法,欢迎在评论区指出)。
下面以iOS (14.6) 为例,在整合了所查阅到的部分资料后,得到以下UIView的extension,可以直接拷贝使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
extension UIView { @discardableResult func applyGradient(_ colours: [UIColor]) -> CAGradientLayer { return applyGradient(colours: colours) } @discardableResult func applyGradient(colours: [UIColor], startPoint: CGPoint = CGPoint(x: 0, y: 0.5), endPoint: CGPoint = CGPoint(x: 1, y: 0.5)) -> CAGradientLayer { let gradient: CAGradientLayer = CAGradientLayer() gradient.frame = self.bounds gradient.colors = colours.map { $0.cgColor } gradient.startPoint = startPoint gradient.endPoint = endPoint gradient.cornerRadius = layer.cornerRadius layer.insertSublayer(gradient, at: 0) return gradient } }
|
实例化一个UIButton
1 2 3 4 5 6 7 8 9 10 11
| class ViewController: UIViewController { @IBOutlet var gradientBtn: UIButton!
override func viewDidLoad() { super.viewDidLoad() gradientBtn.setTitle("Gradient", for: .normal) gradientBtn.layer.cornerRadius = 12 gradientBtn.applyGradient([.systemPink, .systemYellow]) } }
|
Done!
不足之处,欢迎指正。