Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
mergesort committed Jul 4, 2018
0 parents commit b4357f1
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 0 deletions.
15 changes: 15 additions & 0 deletions GradientKit.podspec
@@ -0,0 +1,15 @@
Pod::Spec.new do |spec|
spec.name = 'GradientKit'
spec.summary = 'A simpler way to implement simple gradients on iOS.'
spec.version = '1.0'
spec.license = { :type => 'MIT' }
spec.authors = { 'Joe Fabisevich' => 'github@fabisevi.ch' }
spec.source_files = 'Source/*.swift'
spec.homepage = 'https://github.com/mergesort'
spec.source = { :git => 'https://github.com/mergesort/GradientKit.git', :tag => "#{spec.version}" }

spec.ios.deployment_target = '9.0'
spec.requires_arc = true
spec.social_media_url = 'https://twitter.com/mergesort'
spec.framework = 'UIKit'
end
14 changes: 14 additions & 0 deletions Source/Gradient.swift
@@ -0,0 +1,14 @@
import UIKit

public struct GradientComponents {

let color: UIColor
let location: Double
}

public protocol Gradient {

var startPoint: CGPoint { get }
func makeGradientComponents() -> [GradientComponents]

}
51 changes: 51 additions & 0 deletions Source/GradientView.swift
@@ -0,0 +1,51 @@
import UIKit

public final class GradientView: UIView {

private let gradientLayer = CAGradientLayer()

public var gradient: Gradient = UniformGradient(colors: [.white]) {
didSet {
self.generateGradient()
}
}

// MARK: Initializers

public override init(frame: CGRect) {
super.init(frame: frame)

self.setup()
}

@available(*, unavailable)
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

public override func layoutSubviews() {
super.layoutSubviews()

self.gradientLayer.frame = self.bounds
}
}

private extension GradientView {

func setup() {
self.isUserInteractionEnabled = false
self.layer.addSublayer(self.gradientLayer)
}

func generateGradient() {
self.gradientLayer.startPoint = self.gradient.startPoint

let components = self.gradient.makeGradientComponents()
let colors = components.map { $0.color.cgColor }
let locations = components.map { NSNumber(value: $0.location) }

self.gradientLayer.colors = colors
self.gradientLayer.locations = locations
}

}
105 changes: 105 additions & 0 deletions Source/PercentageGradient.swift
@@ -0,0 +1,105 @@
import Foundation

public enum GradientDirection {

case darkToLight
case lightToDark
}

public struct PercentageGradient: Gradient {

public let baseColor: UIColor
public let direction: GradientDirection
public let percentage: CGFloat
public let startPoint: CGPoint

public init(baseColor: UIColor, direction: GradientDirection, percentage: CGFloat, startPoint: CGPoint = CGPoint(x: 0.5, y: 0.0)) {
self.baseColor = baseColor
self.direction = direction
self.percentage = percentage
self.startPoint = startPoint
}
}

public extension PercentageGradient {

func makeGradientComponents() -> [GradientComponents] {
switch self.direction {

case .darkToLight:
return [
GradientComponents(
color: self.darkerColor(from: baseColor),
location: 0.0
),
GradientComponents(
color: self.lighterColor(from: baseColor),
location: 1.0
)
]

case .lightToDark:
return [
GradientComponents(
color: self.lighterColor(from: baseColor),
location: 0.0
),
GradientComponents(
color: self.darkerColor(from: baseColor),
location: 1.0
)
]
}
}

}


extension PercentageGradient {

func lighterColor(from color: UIColor) -> UIColor {
switch self.direction {

case .darkToLight:
return color

case .lightToDark:
return (color.changedBrightness(byPercentage: self.percentage) ?? UIColor.white)
}
}

func darkerColor(from color: UIColor) -> UIColor {
switch self.direction {

case .darkToLight:
return (color.changedBrightness(byPercentage: -self.percentage) ?? UIColor.black)

case .lightToDark:
return color
}
}
}

private extension UIColor {

func hsba() -> (hue: CGFloat, saturation: CGFloat, brightness: CGFloat, alpha: CGFloat)? {
var hue: CGFloat = .nan
var saturation: CGFloat = .nan
var brightness: CGFloat = .nan
var alpha: CGFloat = .nan

guard self.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) else { return nil }

return (hue: hue, saturation: saturation, brightness: brightness, alpha: alpha)
}

func changedBrightness(byPercentage percent: CGFloat) -> UIColor? {
guard percent != 0 else { return self.copy() as? UIColor }

guard let hsba = self.hsba() else { return nil }

let percentage: CGFloat = min(max(percent, -1), 1)
let newBrightness = min(max(hsba.brightness + percentage, -1), 1)
return UIColor(hue: hsba.hue, saturation: hsba.saturation, brightness: newBrightness, alpha: hsba.alpha)
}
}
27 changes: 27 additions & 0 deletions Source/UniformGradient.swift
@@ -0,0 +1,27 @@
import Foundation

public struct UniformGradient: Gradient {

public let colors: [UIColor]
public let startPoint: CGPoint

public init(colors: [UIColor], startPoint: CGPoint = CGPoint(x: 0.5, y: 0.0)) {
self.colors = colors
self.startPoint = startPoint
}
}

public extension UniformGradient {

func makeGradientComponents() -> [GradientComponents] {
let min = 0.0
let max = 1.0
let by = (max-min)/Double(self.colors.count - 1)

let locations = stride(from: min, through: max, by: by)
.map { $0 }

return zip(colors, locations)
.map { GradientComponents(color: $0, location: $1) }
}
}

0 comments on commit b4357f1

Please sign in to comment.