Learn-iOS-Swift-by-Examples/Quartz2D/QuartzDemo/QuartzGradientView.swift

167 lines
5.6 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples 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)
}
}