QuartzDemo/QuartzGradientView.swift
/* |
Copyright (C) 2017 Apple Inc. All Rights Reserved. |
See LICENSE.txt for this sample’s licensing information |
Abstract: |
Demonstrates using Quartz for drawing gradients. |
*/ |
import UIKit |
class QuartzGradientView: QuartzView { |
enum GradientType: Int { |
case kLinearGradient = 0 |
case kRadialGradient = 1 |
} |
var gradient: CGGradient = { |
var rgb = CGColorSpaceCreateDeviceRGB() |
var colors: [CGFloat] = [ |
204.0 / 255.0, 224.0 / 255.0, 244.0 / 255.0, 1.00, |
29.0 / 255.0, 156.0 / 255.0, 215.0 / 255.0, 1.00, |
0.0 / 255.0, 50.0 / 255.0, 126.0 / 255.0, 1.00 |
] |
return CGGradient(colorSpace: rgb, colorComponents: colors, locations: nil, count: colors.count)! |
}() |
var gradientTypeToDisplay: GradientType = .kLinearGradient { |
didSet(prevGradientTypeToDisplayValue) { |
if prevGradientTypeToDisplayValue != gradientTypeToDisplay { |
setNeedsDisplay() |
} |
} |
} |
var extendsPastStart: Bool = false { |
didSet(prevExtendsPastStartValue) { |
if prevExtendsPastStartValue != extendsPastStart { |
setNeedsDisplay() |
} |
} |
} |
var extendsPastEnd: Bool = false { |
didSet(prevExtendsPastEnd) { |
if prevExtendsPastEnd != extendsPastEnd { |
setNeedsDisplay() |
} |
} |
} |
// Returns an appropriate starting point for the demonstration of a linear gradient |
func demoLGStart(_ bounds: CGRect) -> CGPoint { |
return CGPoint(x: bounds.origin.x, y: bounds.origin.y + bounds.size.height * 0.25) |
} |
// Returns an appropriate ending point for the demonstration of a linear gradient |
func demoLGEnd(_ bounds: CGRect) -> CGPoint { |
return CGPoint(x: bounds.origin.x, y: bounds.origin.y + bounds.size.height * 0.75) |
} |
// Returns the center point for for the demonstration of the radial gradient |
func demoRGCenter(_ bounds: CGRect) -> CGPoint { |
return CGPoint(x: bounds.midX, y: bounds.midY) |
} |
// Returns an appropriate inner radius for the demonstration of the radial gradient |
func demoRGInnerRadius(_ bounds: CGRect) -> CGFloat { |
return min(bounds.size.width, bounds.size.height) * 0.125 |
} |
// Returns an appropriate outer radius for the demonstration of the radial gradient |
func demoRGOuterRadius(_ bounds: CGRect) -> CGFloat { |
return max(bounds.size.width, bounds.size.height) * 0.5 |
} |
func drawingOptions() -> CGGradientDrawingOptions { |
var options: CGGradientDrawingOptions = [] |
if extendsPastStart { |
options.insert(.drawsBeforeStartLocation) |
} |
if extendsPastEnd { |
options.insert(.drawsAfterEndLocation) |
} |
return options |
} |
override func drawInContext(_ context: CGContext) { |
// Use the clip bounding box, sans a generous border |
let clip = context.boundingBoxOfClipPath.insetBy(dx: 20.0, dy: 20.0) |
// Clip to area to draw the gradient, and draw it. Since we are clipping, we save the graphics state |
// so that we can revert to the previous larger area. |
context.savingGState { |
context.clip(to: clip) |
let options: CGGradientDrawingOptions = drawingOptions() |
switch gradientTypeToDisplay { |
case .kLinearGradient: |
// A linear gradient requires only a starting & ending point. |
// The colors of the gradient are linearly interpolated along the line segment connecting these two points |
// A gradient location of 0.0 means that color is expressed fully at the 'start' point |
// a location of 1.0 means that color is expressed fully at the 'end' point. |
// The gradient fills outwards perpendicular to the line segment connectiong start & end points |
// (which is why we need to clip the context, or the gradient would fill beyond where we want it to). |
// The gradient options (last) parameter determines what how to fill the clip area that is "before" and "after" |
// the line segment connecting start & end. |
context.drawLinearGradient(gradient, start: demoLGStart(clip), end: demoLGEnd(clip), options: options) |
case .kRadialGradient: |
// A radial gradient requires a start & end point as well as a start & end radius. |
// Logically a radial gradient is created by linearly interpolating the center, radius and color of each |
// circle using the start and end point for the center, start and end radius for the radius, and the color ramp |
// inherant to the gradient to create a set of stroked circles that fill the area completely. |
// The gradient options specify if this interpolation continues past the start or end points as it does with |
// linear gradients. |
context.drawRadialGradient(gradient, |
startCenter: demoRGCenter(clip), |
startRadius: demoRGInnerRadius(clip), |
endCenter: demoRGCenter(clip), |
endRadius: demoRGOuterRadius(clip), |
options: options) |
} |
} |
// Show the clip rect |
context.setStrokeColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0) |
context.stroke(clip, width: 2.0) |
} |
} |
Copyright © 2017 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2017-09-19