Reputation: 3011
Background
I’m attempting to draw a 3D cone shape as shown in the image below.
I have a method that I use to draw a simple triangle and fill it with a solid color in Swift using a UIBezierPath()
and CAShapeLayer()
.
Question
In Swift code, how can I draw a 3D cone shape or fill the triangle shape I’ve drawn with a complex gradient that gives the triangle shape a 3D effect and effectively a cone appearance?
Code
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var myView: UIView!
override func viewDidLoad() {
let path = UIBezierPath()
path.moveToPoint(CGPoint(x: 0, y: 100))
path.addLineToPoint(CGPoint(x: 200, y: 100))
path.addLineToPoint(CGPoint(x: 100, y: 0))
path.closePath()
let shape = CAShapeLayer()
shape.path = path.CGPath
shape.fillColor = UIColor.grayColor().CGColor
myView.layer.insertSublayer(shape, atIndex: 0)
}
}
Image
Upvotes: 0
Views: 1012
Reputation: 15052
I was able to achieve your goal making use of CGGradientLayer
with a type of conic
. The trick is to use the triangle shape as a mask for the gradient.
Here is an example that can be run in a Swift Playground. Comments in the code.
import UIKit
import PlaygroundSupport
class ConeView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
// Just for display
backgroundColor = .yellow
// Create the triangle to be used as the gradient's mask
// Base the size of the triangle on the view's frame
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: frame.height))
path.addLine(to: CGPoint(x: frame.width, y: frame.height))
path.addLine(to: CGPoint(x: frame.width / 2, y: 0))
path.close()
// Create a shape from the path
let shape = CAShapeLayer()
shape.path = path.cgPath
// Create a conical gradient and mask it with the triangle shape
let gradientLayer = CAGradientLayer()
gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.0)
gradientLayer.endPoint = CGPoint(x: 0.5, y: -0.5)
gradientLayer.type = .conic
// Change the white value of the center color to adjust the center highlight brightness as desired
gradientLayer.colors = [UIColor.black.cgColor, UIColor(white: 0.9, alpha: 1.0).cgColor, UIColor.black.cgColor]
// Tweak the 1st and 3rd number as desired.
// The closer to 0.5 the darker the cone edges will be.
// The further from 0.5 the lighter the cone edges will be.
gradientLayer.locations = [ 0.38, 0.5, 0.62 ]
gradientLayer.frame = bounds
gradientLayer.mask = shape
layer.insertSublayer(gradientLayer, at: 0)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// Set whatever size you want for the view
PlaygroundPage.current.liveView = ConeView(frame: CGRect(x: 0, y: 0, width: 200, height: 100))
Here's the result (the black border is not part of the view, just part of the screen capture):
Upvotes: 0