How to create a gradiated triangle image - ios

Here's the code I have to create a gradiated triangle (a triangle that, instead of being a flat color, has a color gradient in it):
extension UIImage {
struct GradientPoint {
var location: CGFloat
var color: UIColor
}
static func gradiatedTriangle(side: CGFloat)->UIImage {
UIGraphicsBeginImageContextWithOptions(CGSize(width: side, height: side), false, 0)
let ctx = UIGraphicsGetCurrentContext()!
ctx.saveGState()
//create gradient and draw it
let gradientPoints = [UIImage.GradientPoint(location: 0, color: UIColor.from(rgb: 0xff0000)), UIImage.GradientPoint(location: 1, color: UIColor.from(rgb: 0xd0d0d0))]
let gradient = CGGradient(colorSpace: CGColorSpaceCreateDeviceRGB(), colorComponents: gradientPoints.flatMap{$0.color.cgColor.components}.flatMap{$0}, locations: gradientPoints.map{$0.location}, count: gradientPoints.count)!
ctx.drawLinearGradient(gradient, start: CGPoint.zero, end: CGPoint(x: 0, y: side), options: CGGradientDrawingOptions())
//draw triangle
ctx.beginPath()
ctx.move(to: CGPoint(x: side / 2, y: side))
ctx.addLine(to: CGPoint(x: 0, y: 0))
ctx.addLine(to: CGPoint(x: side, y: 0))
ctx.closePath()
ctx.drawPath(using: .fill)
ctx.restoreGState()
let img = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return img
}
}
However, the image that's returned has a square gradient in the background and a black triangle on top of it. I can make the fill clear, but I don't know how to trim the gradient layer around the path so that only a triangle remains. How can I trim away the gradient layer that's outside the path I drew?

Replace your code with this one, first you need to add the path, then ctx.clip() to clip the context and then draw your gradient
import UIKit
extension UIImage {
struct GradientPoint {
var location: CGFloat
var color: UIColor
}
static func gradiatedTriangle(side: CGFloat)->UIImage {
UIGraphicsBeginImageContextWithOptions(CGSize(width: side, height: side), false, 0)
let ctx = UIGraphicsGetCurrentContext()!
//draw triangle
ctx.beginPath()
ctx.move(to: CGPoint(x: side / 2, y: side))
ctx.addLine(to: CGPoint(x: 0, y: 0))
ctx.addLine(to: CGPoint(x: side, y: 0))
ctx.closePath()
ctx.clip()
//create gradient and draw it
let gradientPoints = [UIImage.GradientPoint(location: 0, color: UIColor.red), UIImage.GradientPoint(location: 1, color: UIColor.blue)]
let gradient = CGGradient(colorSpace: CGColorSpaceCreateDeviceRGB(), colorComponents: gradientPoints.flatMap{$0.color.cgColor.components}.flatMap{$0}, locations: gradientPoints.map{$0.location}, count: gradientPoints.count)!
ctx.drawLinearGradient(gradient, start: CGPoint.zero, end: CGPoint(x: 0, y: side), options: CGGradientDrawingOptions())
let img = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return img
}
}
Result
Hope this helps you, Best regards

Related

add rounding for the outline swift

I have a code that adds an outline of the required width and color to an image and it works well
But I still need to adjust the rounding for the contour, please tell me in which direction should I start?
There are two functions here that do the job of laying the outline.
func colorized(with color: UIColor = .white) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, scale)
defer {
UIGraphicsEndImageContext()
}
guard let context = UIGraphicsGetCurrentContext(), let cgImage = cgImage else { return self }
let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
color.setFill()
context.translateBy(x: 0, y: size.height)
context.scaleBy(x: 1.0, y: -1.0)
context.clip(to: rect, mask: cgImage)
context.fill(rect)
guard let colored = UIGraphicsGetImageFromCurrentImageContext() else { return self }
return colored
}
/**
Returns the stroked version of the fransparent image with the given stroke color and the thickness.
- Parameters:
- color: The colors to user. By defaut, uses the ``UIColor.white`
- thickness: the thickness of the border. Default to `2`
- quality: The number of degrees (out of 360): the smaller the best, but the slower. Defaults to `10`.
- Returns: the stroked version of the image, or self if something was wrong
*/
func stroked(with color: UIColor = .red, thickness: CGFloat = 2, quality: CGFloat = 10) -> UIImage {
guard let cgImage = cgImage else { return self }
// Colorize the stroke image to reflect border color
let strokeImage = colorized(with: color)
guard let strokeCGImage = strokeImage.cgImage else { return self }
/// Rendering quality of the stroke
let step = quality == 0 ? 10 : abs(quality)
let oldRect = CGRect(x: thickness, y: thickness, width: size.width, height: size.height).integral
let newSize = CGSize(width: size.width + 2 * thickness, height: size.height + 2 * thickness)
let translationVector = CGPoint(x: thickness, y: 0)
UIGraphicsBeginImageContextWithOptions(newSize, false, scale)
guard let context = UIGraphicsGetCurrentContext() else { return self }
defer {
UIGraphicsEndImageContext()
}
context.translateBy(x: 0, y: newSize.height)
context.scaleBy(x: 1.0, y: -1.0)
context.interpolationQuality = .high
for angle: CGFloat in stride(from: 0, to: 360, by: step) {
let vector = translationVector.rotated(around: .zero, byDegrees: angle)
let transform = CGAffineTransform(translationX: vector.x, y: vector.y)
context.concatenate(transform)
context.draw(strokeCGImage, in: oldRect)
let resetTransform = CGAffineTransform(translationX: -vector.x, y: -vector.y)
context.concatenate(resetTransform)
}
context.draw(cgImage, in: oldRect)
guard let stroked = UIGraphicsGetImageFromCurrentImageContext() else { return self }
return stroked
}
I tried many options but most of the answers are just adding a conerRadius to the UIImageView (this doesn't work)

gradient in for multipel UIBezierPath

I'm supposed to create this.
I did search the google, youtube, and StackOverflow, and the code below is the result of my research.
#IBDesignable class TriangleView2: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
let gradient = CAGradientLayer()
override func draw(_ rect: CGRect) {
//draw the line of UIBezierPath
let path1 = UIBezierPath()
path1.move(to: CGPoint(x: rect.minX - 100, y: rect.maxY - 80))
path1.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
path1.addLine(to: CGPoint(x: (rect.maxX + 90 ), y: rect.minY/2 ))
path1.close()
// add clipping path. this draws an imaginary line (to create bounds) from the
//ends of the UIBezierPath line down to the bottom of the screen
let clippingPath = path1.copy() as! UIBezierPath
clippingPath.move(to: CGPoint(x: rect.minX - 100, y: rect.maxY - 80))
clippingPath.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
clippingPath.addLine(to: CGPoint(x: (rect.maxX + 90 ), y: rect.minY/2 ))
clippingPath.close()
clippingPath.addClip()
// create and add the gradient
let colors = [theme.current.profile_start_view1.cgColor, theme.current.profile_end_view1.cgColor]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let colorLocations:[CGFloat] = [0.0, 1.0]
let gradient = CGGradient(colorsSpace: colorSpace,
colors: colors as CFArray,
locations: colorLocations)
let context = UIGraphicsGetCurrentContext()
let startPoint = CGPoint(x: 1, y: 1)
let endPoint = CGPoint(x: 1, y: bounds.maxY)
// and lastly, draw the gradient.
context!.drawLinearGradient(gradient!, start: startPoint, end:
endPoint, options: CGGradientDrawingOptions.drawsAfterEndLocation)
}
}
Right not I have 2 views ( will be 3 if I could complete it) with some differences.
The result is this.
These 2 views do not have the same colour, but as you can see both views have the same gradient with the same direction.
Does anyone have any suggestion?
This is somewhat similar to Codo's answer but you only need 4 points.
class FourGradientsView: UIView {
override func draw(_ rect: CGRect) {
let ctx = UIGraphicsGetCurrentContext()!
// Points of area to draw - adjust these 4 variables as needed
let tl = CGPoint(x: 0, y: 0)
let tr = CGPoint(x: bounds.width * 1.3, y: 0)
let bl = CGPoint(x: -bounds.width * 1.8, y: bounds.height * 1.4)
let br = CGPoint(x: bounds.width * 1.3, y: bounds.height * 2)
// Find the intersection of the two crossing diagonals
let s1x = br.x - tl.x
let s1y = br.y - tl.y
let s2x = tr.x - bl.x
let s2y = tr.y - bl.y
//let s = (-s1y * (tl.x - bl.x) + s1x * (tl.y - bl.y)) / (-s2x * s1y + s1x * s2y)
let t = ( s2x * (tl.y - bl.y) - s2y * (tl.x - bl.x)) / (-s2x * s1y + s1x * s2y)
let center = CGPoint(x: tl.x + (t * s1x), y: tl.y + (t * s1y))
// Create clipping region to avoid drawing where we don't want any gradients
ctx.saveGState()
let clip = CGPoint(x: 0, y: bounds.height * 0.7)
let clipPath = UIBezierPath()
clipPath.move(to: CGPoint(x: 0, y: 0))
clipPath.addLine(to: clip)
clipPath.addLine(to: CGPoint(x: bounds.width, y: bounds.height))
clipPath.addLine(to: CGPoint(x: bounds.width, y: 0))
clipPath.close()
clipPath.addClip()
// Use these two colors for all 4 gradients (adjust as needed)
let colors = [
UIColor(hue: 120/360, saturation: 1, brightness: 0.85, alpha: 1).cgColor,
UIColor(hue: 120/360, saturation: 1, brightness: 0.3, alpha: 1).cgColor
] as CFArray
// The common gradient
let gradient = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(), colors: colors, locations: nil)!
// Top gradient
ctx.saveGState()
let pathTop = UIBezierPath()
pathTop.move(to: tl)
pathTop.addLine(to: tr)
pathTop.addLine(to: center)
pathTop.close()
pathTop.addClip()
ctx.drawLinearGradient(gradient, start: CGPoint(x: bounds.width, y: 0), end: CGPoint(x: 0, y: 0), options: [])
ctx.restoreGState()
// Right gradient
ctx.saveGState()
let pathRight = UIBezierPath()
pathRight.move(to: tr)
pathRight.addLine(to: br)
pathRight.addLine(to: center)
pathRight.close()
pathRight.addClip()
ctx.drawLinearGradient(gradient, start: CGPoint(x: bounds.width, y: bounds.height), end: CGPoint(x: bounds.width, y: 0), options: [])
ctx.restoreGState()
// Bottom gradient
ctx.saveGState()
let pathBottom = UIBezierPath()
pathBottom.move(to: br)
pathBottom.addLine(to: bl)
pathBottom.addLine(to: center)
pathBottom.close()
pathBottom.addClip()
ctx.drawLinearGradient(gradient, start: CGPoint(x: 0, y: bounds.height), end: CGPoint(x: bounds.width, y: bounds.height), options: [])
ctx.restoreGState()
// Left gradient
ctx.saveGState()
let pathLeft = UIBezierPath()
pathLeft.move(to: tl)
pathLeft.addLine(to: bl)
pathLeft.addLine(to: center)
pathLeft.close()
pathLeft.addClip()
ctx.drawLinearGradient(gradient, start: CGPoint(x: 0, y: 0), end: CGPoint(x: 0, y: bounds.height), options: [])
ctx.restoreGState()
ctx.restoreGState()
}
}
let grView = FourGradientsView(frame: CGRect(x: 0, y: 0, width: 320, height: 320))
grView.backgroundColor = .black
You wrote code that always uses the same start and end color, always uses the same color locations, and always uses the same start and end points. Of course the gradients have the same gradient with the same direction.
Give your views gradient start point and end point properties as well as start and end colors. Set the gradient start points for your gradient views in your view controller's layoutDidChange() method, based on the bounds of the views. (That way you handle device rotation and different sized devices correctly.
Here's an example that you can run directly in the playground.
As you want four gradients and as gradients are draw using clipping, the graphics context is saved and restored several times (to reset the clipping).
The grading start and end point is one of the clipping corners. That's not needed. You can (and probably) should use separate points. To achieve the desired result, you sometimes want to use a start or end point considerably outside the the clipping area.
import UIKit
import PlaygroundSupport
class TriangleView2: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func draw(_ rect: CGRect) {
let colors = [UIColor(red: 50/255.0, green: 242/255.0, blue: 111/255.0, alpha: 1).cgColor,
UIColor(red: 29/255.0, green: 127/255.0, blue: 60/255.0, alpha: 1).cgColor]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let colorLocations:[CGFloat] = [0.0, 1.0]
let gradient = CGGradient(colorsSpace: colorSpace,
colors: colors as CFArray,
locations: colorLocations)!
let options: CGGradientDrawingOptions = [CGGradientDrawingOptions.drawsBeforeStartLocation, CGGradientDrawingOptions.drawsAfterEndLocation]
let p1 = CGPoint(x: 0, y: 0)
let p2 = CGPoint(x: bounds.width, y: 0)
let p3 = CGPoint(x: bounds.width, y: 20)
let p4 = CGPoint(x: bounds.width / 3, y: 140)
let p5 = CGPoint(x: 0, y: 200)
let p6 = CGPoint(x: bounds.width * 5 / 8, y: 260)
let p7 = CGPoint(x: 0, y: 230)
let p8 = CGPoint(x: bounds.width, y: 280)
let context = UIGraphicsGetCurrentContext()!
context.saveGState()
let path1 = UIBezierPath()
path1.move(to: p1)
path1.addLine(to: p2)
path1.addLine(to: p3)
path1.addLine(to: p4)
path1.close()
path1.addClip()
context.drawLinearGradient(gradient, start: p3, end: p1, options: options)
context.restoreGState()
context.saveGState()
let path2 = UIBezierPath()
path2.move(to: p1)
path2.addLine(to: p4)
path2.addLine(to: p5)
path2.close()
path2.addClip()
context.drawLinearGradient(gradient, start: p1, end: p5, options: options)
context.restoreGState()
context.saveGState()
let path3 = UIBezierPath()
path3.move(to: p3)
path3.addLine(to: p8)
path3.addLine(to: p6)
path3.addLine(to: p4)
path3.close()
path3.addClip()
context.drawLinearGradient(gradient, start: p8, end: p3, options: options)
context.restoreGState()
context.saveGState()
let path4 = UIBezierPath()
path4.move(to: p5)
path4.addLine(to: p4)
path4.addLine(to: p6)
path4.addLine(to: p7)
path4.close()
path4.addClip()
context.drawLinearGradient(gradient, start: p7, end: p6, options: options)
context.restoreGState()
}
}
let main = TriangleView2(frame: CGRect(x: 0, y: 0, width: 320, height: 500))
PlaygroundPage.current.liveView = main
Update
One more thing: Do not use the rect parameter to derive the geometry of your shapes. rect does not refer to the view size or position. Instead, it's area that needs to be redrawn. If iOS decides only part of your view needs to be redrawn, your code will draw the wrong shape.

How to create a triangle UIImage

How can I create a triangle UIImage? Here's how I'm doing it now, but it's not producing any image at all.
extension UIImage {
static func triangle(side: CGFloat, color: UIColor)->UIImage {
UIGraphicsBeginImageContextWithOptions(CGSize(width: side, height: side), false, 0)
let ctx = UIGraphicsGetCurrentContext()!
ctx.saveGState()
ctx.beginPath()
ctx.move(to: CGPoint(x: side / 2, y: 0))
ctx.move(to: CGPoint(x: side, y: side))
ctx.move(to: CGPoint(x: 0, y: side))
ctx.move(to: CGPoint(x: side / 2, y: 0))
ctx.closePath()
ctx.setFillColor(color.cgColor)
ctx.restoreGState()
let img = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return img
}
}
Your path does not contain any lines, so there's no region to fill. In addition you are not drawing the path.
Try something like this:
static func triangle(side: CGFloat, color: UIColor)->UIImage {
UIGraphicsBeginImageContextWithOptions(CGSize(width: side, height: side), false, 0)
let ctx = UIGraphicsGetCurrentContext()!
ctx.saveGState()
ctx.beginPath()
ctx.move(to: CGPoint(x: side / 2, y: 0))
//### Add lines
ctx.addLine(to: CGPoint(x: side, y: side))
ctx.addLine(to: CGPoint(x: 0, y: side))
//ctx.addLine(to: CGPoint(x: side / 2, y: 0)) //### path is automatically closed
ctx.closePath()
ctx.setFillColor(color.cgColor)
ctx.drawPath(using: .fill) //### draw the path
ctx.restoreGState()
let img = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return img
}
You might just use UIBezierPath and not use CoreGraphics at all. Furthermore, nowadays we’d use UIGraphicsImageRenderer:
extension UIImage {
static func triangle(side: CGFloat, color: UIColor) -> UIImage {
return UIGraphicsImageRenderer(size: CGSize(width: side, height: side)).image { _ in
let path = UIBezierPath()
path.move(to: CGPoint(x: side / 2, y: 0))
path.addLine(to: CGPoint(x: side, y: side))
path.addLine(to: CGPoint(x: 0, y: side))
path.close()
color.setFill()
path.fill()
}
}
}
For UIBezierPath version that still uses UIGraphicsBeginImageContextWithOptions, see previous revision of this answer.
OOPer told you about your lack of lines, and failure to actually draw the triangle.
In addition to that, I would suggest avoiding mucking around with graphics contexts. UIBezierPath makes it cleaner and easier to draw without having to worry about contexts. Also, you don't need to save and restore contexts since you are creating a temporary context and then immediately discarding it.
Here is a complete playground that draws your triangle (and fills and strokes the image rectangle so it's easier to see - you'd remove the stroke and probably fill the shape with UIColor.clear instead.)
import UIKit
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
extension UIImage {
static func triangle(side: CGFloat, color: UIColor)->UIImage {
UIGraphicsBeginImageContextWithOptions(CGSize(width: side, height: side), false, 0)
//First fill the bounds with white
let rectPath = UIBezierPath(rect: CGRect(x:0, y: 0, width: side, height: side))
UIColor.white.setFill() //Use clear if you want your image to only contain the triangle.
rectPath.fill()
//Now build the triangle path
let path = UIBezierPath()
path.move(to: CGPoint(x: side / 2, y: 0))
path.addLine(to: CGPoint(x: side, y: side))
path.addLine(to: CGPoint(x: 0, y: side))
path.close() //Closing the path draws the final line
color.setFill()
path.fill()
//Stroke the outer path in gray so you can see the bounds - remove if desired
UIColor.gray.setStroke()
rectPath.stroke()
let img = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return img
}
}
let imageView = UIImageView(frame: CGRect(x:0, y: 0, width: 200, height: 200))
PlaygroundPage.current.liveView = imageView
imageView.image = UIImage.triangle(side: 200.0, color: UIColor.yellow)

Gradient over UIImageView

I've been trying to fill an image view with a gradient layer, but I can't seem to make it work, I tried to create CAGradientLayer, applied 2 colors on it then applied it as a mask to the main image layer.
let gradient = CAGradientLayer()
gradient.frame = (self.imageView?.bounds)!
gradient.colors = [UIColor.blue.cgColor, UIColor.purple.cgColor]
gradient.startPoint = CGPoint(x: 0.0, y: 0.5)
gradient.endPoint = CGPoint(x: 0.5, y: 1.0)
gradient.locations = [0, 1]
self.imageView?.layer.mask = gradient
This is what I have, and this is what I want as a result:
UPDATE:
Found the solution here.
You can do something like this:
var gradient = CAGradientLayer()
gradient.frame = imageView.bounds
gradient.colors = [UIColor.blue.cgColor, UIColor.purple.cgColor]
imageView.layer.insertSublayer(gradient, at: 0)
I got this answer. Add extension of UIImage and just pass colours list to apply gradient.
import UIKit
extension UIImage {
func tintedWithLinearGradientColors(colorsArr: [CGColor]) -> UIImage {
UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale);
guard let context = UIGraphicsGetCurrentContext() else {
return UIImage()
}
context.translateBy(x: 0, y: self.size.height)
context.scaleBy(x: 1, y: -1)
context.setBlendMode(.normal)
let rect = CGRect.init(x: 0, y: 0, width: size.width, height: size.height)
// Create gradient
let colors = colorsArr as CFArray
let space = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(colorsSpace: space, colors: colors, locations: nil)
// Apply gradient
context.clip(to: rect, mask: self.cgImage!)
context.drawLinearGradient(gradient!, start: CGPoint(x: 0, y: 0), end: CGPoint(x: 0, y: self.size.height), options: .drawsAfterEndLocation)
let gradientImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return gradientImage!
}
}

Draw gradient under UIBezierPath

I have drawn a curved line. I want to put a gradient from the view all the way up to the line (so that the gradient curves along with the line.)
edit: here is a photo of what the code below produces:
I know how to draw the line, and I know how to add a regular gradient, but just not the two together. Here is my code:
override func drawRect(rect: CGRect) {
// draw the curved line, this code works just fine.
let path1 = UIBezierPath()
path1.lineWidth = 1.1
UIColor.greenColor().setStroke()
path1.moveToPoint(CGPoint(x: 0, y: bounds.height/2))
path1.addQuadCurveToPoint(CGPoint(x: bounds.width, y: bounds.height/2), controlPoint: CGPoint(x: bounds.width/2, y: (bounds.height * 0.75)))
path1.stroke()
// my attempt to draw the gradient:
let gradient = CAGradientLayer()
gradient.startPoint = CGPoint(x: 1, y: 1)
gradient.endPoint = CGPoint(x: 0, y: 0)
let colors = [UIColor.whiteColor().CGColor, UIColor(red: 0, green: 1, blue: 1, alpha: 0.4).CGColor]
gradient.colors = colors
// the following line is where I need help
gradient.frame = CGRectMake(0, 475, bounds.width, path1.bounds.height)
layer.addSublayer(gradient)
}
what can I set gradient.frame equal to so that it's upper limit is the previously drawn path? Answer in Swift please (i've seen a lot of other questions on this subject but they are all in objective C)
Thanks
I have found the answer.
The following code gave me this:
.
Here is the code:
override func drawRect(rect: CGRect) {
//draw the line of UIBezierPath
let path1 = UIBezierPath()
path1.lineWidth = 1.1
UIColor(white: 1, alpha: 1).setStroke()
path1.moveToPoint(CGPoint(x: 0, y: bounds.height/2))
path1.addQuadCurveToPoint(CGPoint(x: bounds.width, y: bounds.height/2), controlPoint: CGPoint(x: bounds.width/2, y: (bounds.height * 0.65)))
path1.stroke()
// add clipping path. this draws an imaginary line (to create bounds) from the
//ends of the UIBezierPath line down to the bottom of the screen
let clippingPath = path1.copy() as! UIBezierPath
clippingPath.addLineToPoint(CGPoint(x: self.bounds.width, y: self.bounds.height))
clippingPath.addLineToPoint(CGPoint(x: 0, y: bounds.height))
clippingPath.closePath()
clippingPath.addClip()
// create and add the gradient
let colors = [UIColor(red: 0, green: 1, blue: 1, alpha: 0.45).CGColor, UIColor.whiteColor().CGColor]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let colorLocations:[CGFloat] = [0.0, 1.0]
let gradient = CGGradientCreateWithColors(colorSpace,
colors,
colorLocations)
let context = UIGraphicsGetCurrentContext()
let startPoint = CGPoint(x: 1, y: 1)
let endPoint = CGPoint(x: 1, y: bounds.maxY)
// and lastly, draw the gradient.
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, CGGradientDrawingOptions.DrawsAfterEndLocation)
}

Resources