iOS Can set stroke line with gradient - ios

I have UIView for drawing.
Can i change stroke line from default
CGContextSetStrokeColorWithColor(context, UIColor.blackColor().CGColor)
to https://www.img.in.th/image/79xF
or http://catheria.com/wp-content/uploads/2015/10/StrokeLinear.png
below is code draw radius gradient
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
let ctx0 = UIGraphicsGetCurrentContext()
let colorSpace: CGColorSpaceRef = CGColorSpaceCreateDeviceRGB()!
let locations: [CGFloat] = [0.0, 0.4, 1.0]
let arrColor = [UIColor.blackColor().CGColor,UIColor.blackColor().CGColor, UIColor.clearColor().CGColor]
let _gradient: CGGradientRef = CGGradientCreateWithColors(colorSpace, arrColor, locations)!
CGContextDrawRadialGradient(ctx0, _gradient, CGPoint(x: size.width/2, y: size.height/2), CGFloat(0), CGPoint(x: size.width/2, y: size.height/2), CGFloat(60), CGGradientDrawingOptions())
let _img0 = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

Related

CAGradientLayer different between iOS 12 and iOS 13

I use this code to generate an UIImage from a gradient.
func buildGradientImage() -> UIImage? {
let gradientLayer = CAGradientLayer()
gradientLayer.frame = CGRect(x: 0, y: 0, width: 375, height: 667)
gradientLayer.type = .radial
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.0)
gradientLayer.endPoint = CGPoint(x: 1.2, y: 1.0)
gradientLayer.colors = [UIColor.red.cgColor, UIColor.green.cgColor]
var gradientImage:UIImage?
UIGraphicsBeginImageContext(gradientLayer.frame.size)
if let context = UIGraphicsGetCurrentContext() {
gradientLayer.render(in: context)
gradientImage = UIGraphicsGetImageFromCurrentImageContext()
}
UIGraphicsEndImageContext()
return gradientImage
}
For some reason the resulting image is different between iOS 12 and iOS 13-14.
Red seems to expand more on the iOS 12 gradient.
Someone know why there is this difference? Shouldn't the code generate the same gradient?

How to gradient fill custom UIView using Swift?

I have a custom triangle UIView which I want to fill with custom gradient color.
override func draw(_ rect: CGRect) {
let widerStartingPoint = CGFloat(240)
guard let context = UIGraphicsGetCurrentContext() else { return }
context.beginPath()
context.move(to: CGPoint(x: rect.minX - widerStartingPoint, y: rect.maxY))
context.addLine(to: CGPoint(x: rect.maxX + widerStartingPoint, y: rect.maxY))
context.addLine(to: CGPoint(x: (rect.maxX / 2.0), y: rect.minY))
context.closePath()
let colors = [firstColor.cgColor, secondColor.cgColor ,thirdColor.cgColor] as CFArray
let colorSpace = CGColorSpaceCreateDeviceRGB()
let colorLocations: [CGFloat] = [0.0, 0.5 ,1.0]
let startPoint = CGPoint.zero
let endPoint = CGPoint(x: 0, y: bounds.height)
let gradient = CGGradient(colorsSpace: colorSpace,
colors: colors as CFArray,
locations: colorLocations)!
// I need to find a way to change below color with gradient color
context.setFillColor(red: 1.0, green: 0.5, blue: 0.0, alpha: 0.60)
context.fillPath()
}
I tried to find other setFillColor methods, but they are only allowing assigning single color.
Thank you for your time.
Instead of using setFillColor I used context.drawLinearGradient(gradient, start: startPoint, end: endPoint, options: []) also added clipping to the path. So working code is below!:
override func draw(_ rect: CGRect) {
let widerStartingPoint = CGFloat(240)
guard let context = UIGraphicsGetCurrentContext() else { return }
context.beginPath()
context.move(to: CGPoint(x: rect.minX - widerStartingPoint, y: rect.maxY))
context.addLine(to: CGPoint(x: rect.maxX + widerStartingPoint, y: rect.maxY))
context.addLine(to: CGPoint(x: (rect.maxX / 2.0), y: rect.minY))
context.closePath()
// This was missing!
context.clip()
let colors = [firstColor.cgColor, secondColor.cgColor ,thirdColor.cgColor] as CFArray
let colorSpace = CGColorSpaceCreateDeviceRGB()
let colorLocations: [CGFloat] = [0.0, 0.5 ,1.0]
let startPoint = CGPoint.zero
let endPoint = CGPoint(x: 0, y: bounds.height)
let gradient = CGGradient(colorsSpace: colorSpace,
colors: colors as CFArray,
locations: colorLocations)!
// Also used this method
context.drawLinearGradient(gradient, start: startPoint, end: endPoint, options: [])
context.fillPath()
}

Fill Path on Intersecting UIBezierPath

Any idea on how to fill all the paths in here. What is currently happening is that I draw a rectangle path on my view then add small circles in between but it seems that if the circle and rectangle intersects, the white fill color is showing. What I would want is show still the gradient layer. Any help? My current code is below.
func addGradientLayer() {
let gradientLayer = CAGradientLayer()
gradientLayer.frame = bounds
let startColor = UIColor.create(withHexOrName: OurPayStatesViewUX.GradientColorStart)
let endColor = UIColor.create(withHexOrName: OurPayStatesViewUX.GradientColorEnd)
gradientLayer.colors = [startColor.CGColor, endColor.CGColor]
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = CGPoint(x: 1, y: 0)
layer.insertSublayer(gradientLayer, atIndex: 0)
}
func createOverlay(view: UIView, circleLocations: [CGPoint]) {
maskLayer?.removeFromSuperlayer()
let radius: CGFloat = view.frame.height/2
let path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: view.bounds.size.width, height: view.bounds.size.height), cornerRadius: 0)
for i in circleLocations {
// Create a circle path in each of the state views
let circlePath = UIBezierPath(roundedRect: CGRect(x: i.x, y: i.y, width: 2 * radius, height: 2 * radius), cornerRadius: radius)
path.appendPath(circlePath)
}
let rect = createRectangle(startPointX: 0, endPointX: view.bounds.size.width)
path.appendPath(rect)
path.usesEvenOddFillRule = true
let fillLayer = CAShapeLayer()
fillLayer.path = path.CGPath
fillLayer.fillRule = kCAFillRuleEvenOdd
fillLayer.fillColor = backgroundColor?.CGColor ?? UIColor.whiteColor().CGColor
fillLayer.opacity = 1
maskLayer = fillLayer
layer.addSublayer(fillLayer)
}
func createRectangle(startPointX startPointX: CGFloat, endPointX: CGFloat) -> UIBezierPath {
let rectHeight: CGFloat = 6
let path = UIBezierPath(rect: CGRect(x: startPointX, y: frame.height/2 - rectHeight/2, width: endPointX - startPointX, height: rectHeight))
return path
}

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