GradientDesignable.swift 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. //
  2. // Created by Jake Lin on 12/4/15.
  3. // Copyright © 2015 IBAnimatable. All rights reserved.
  4. //
  5. import UIKit
  6. public protocol GradientDesignable: class {
  7. var gradientMode: GradientMode { get set }
  8. var startColor: UIColor? { get set }
  9. var endColor: UIColor? { get set }
  10. var predefinedGradient: GradientType? { get set }
  11. var startPoint: GradientStartPoint { get set }
  12. }
  13. // MARK: - UIView
  14. extension GradientDesignable where Self: UIView {
  15. public func configureGradient() {
  16. configureGradient(in: self)
  17. }
  18. }
  19. // MARK: - NavigationBar
  20. extension GradientDesignable where Self: UINavigationBar {
  21. public func configureGradient() {
  22. guard let gradientLayer = makeGradientLayer() else {
  23. setBackgroundImage(nil, for: .default)
  24. return
  25. }
  26. let statusBarHeight: CGFloat
  27. if #available(iOS 13, *) {
  28. statusBarHeight = 0 /*self.window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0 */
  29. } else {
  30. statusBarHeight = UIApplication.shared.statusBarFrame.height
  31. }
  32. let height = bounds.height + statusBarHeight
  33. let navBarFrame = CGRect(x: 0, y: 0, width: bounds.width, height: height)
  34. gradientLayer.frame = navBarFrame
  35. gradientLayer.cornerRadius = layer.cornerRadius
  36. let image = gradientLayer.makeImage()
  37. setBackgroundImage(image, for: .default)
  38. }
  39. }
  40. // MARK: - Layers
  41. extension CALayer {
  42. fileprivate func makeImage() -> UIImage? {
  43. UIGraphicsBeginImageContext(frame.size)
  44. render(in: UIGraphicsGetCurrentContext()!)
  45. let outputImage = UIGraphicsGetImageFromCurrentImageContext()
  46. UIGraphicsEndImageContext()
  47. return outputImage
  48. }
  49. }
  50. // MARK: - Common
  51. extension GradientDesignable {
  52. func configureGradient(in view: UIView) {
  53. view.subviews.filter { $0 is PrivateGradientView }.forEach {
  54. $0.removeFromSuperview()
  55. }
  56. guard let gradientLayer = makeGradientLayer() else {
  57. return
  58. }
  59. gradientLayer.cornerRadius = view.layer.cornerRadius
  60. gradientLayer.frame = view.bounds
  61. let gradientView = PrivateGradientView(frame: view.bounds, gradientLayer: gradientLayer)
  62. view.insertSubview(gradientView, at: 0)
  63. }
  64. private func makeGradientLayer() -> CALayer? {
  65. guard let colors = gradientColors() else {
  66. return nil
  67. }
  68. switch gradientMode {
  69. case .linear:
  70. return makeLinearLayer(colors: colors)
  71. case .radial:
  72. return makeRadialLayer(colors: colors)
  73. case .conical:
  74. return makeConicalLayer(colors: colors)
  75. }
  76. }
  77. private func gradientColors() -> [CGColor]? {
  78. if let startColor = startColor, let endColor = endColor {
  79. return [startColor.cgColor, endColor.cgColor]
  80. } else if let startColor = predefinedGradient?.colors.start, let endColor = predefinedGradient?.colors.end {
  81. return [startColor.cgColor, endColor.cgColor]
  82. }
  83. return nil
  84. }
  85. private func makeLinearLayer(colors: [CGColor]) -> CAGradientLayer {
  86. let layer = CAGradientLayer()
  87. layer.colors = colors
  88. layer.startPoint = startPoint.startPoint
  89. layer.endPoint = startPoint.endPoint
  90. return layer
  91. }
  92. private func makeRadialLayer(colors: [CGColor]) -> RadialGradientLayer {
  93. let layer = RadialGradientLayer()
  94. layer.colors = colors
  95. layer.startPoint = startPoint.startPoint
  96. layer.endPoint = startPoint.endPoint
  97. return layer
  98. }
  99. private func makeConicalLayer(colors: [CGColor]) -> ConicalGradientLayer {
  100. let layer = ConicalGradientLayer()
  101. layer.colors = colors
  102. layer.startPoint = startPoint.startPoint
  103. layer.endPoint = startPoint.endPoint
  104. return layer
  105. }
  106. }
  107. // MARK: - PrivateGradientView
  108. private class PrivateGradientView: UIView {
  109. init(frame: CGRect, gradientLayer: CALayer) {
  110. super.init(frame: frame)
  111. layer.insertSublayer(gradientLayer, at: 0)
  112. autoresizingMask = [.flexibleWidth, .flexibleHeight]
  113. }
  114. required init?(coder aDecoder: NSCoder) {
  115. fatalError("init(coder:) has not been implemented")
  116. }
  117. override class var layerClass: AnyClass {
  118. return CALayer.self
  119. }
  120. }