I am trying to cut one edge of UIView using Bezier path but i am unable to do it, could anyone please enlighten me ?
Thank You
You can try to assign this to the view
class RightView : UIView {
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else { return }
context.beginPath()
context.move(to: CGPoint(x: rect.maxX, y: rect.minY))
context.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
context.addLine(to: CGPoint(x:rect.maxX - 50, y: rect.maxY))
context.closePath()
context.setFillColor(UIColor.white.cgColor)
context.fillPath()
}
override func awakeFromNib() {
super.awakeFromNib()
self.layer.borderColor = UIColor.black.cgColor
self.layer.borderWidth = 1
}
}
Related
I would like to draw a triangle view and change the filled color programmatically.
Following is my code.
import UIKit
class ViewController: UIViewController {
let triangleView = TriangleView()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
triangleView.frame = CGRect(x: 0,
y: 100,
width: 50,
height: 50)
self.view.addSubview(triangleView)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
triangleView.drawColor(color: .yellow)
}
}
class TriangleView: UIView {
let path = UIBezierPath()
override func draw(_ rect: CGRect) {
print("TriangleView draw")
path.move(to: CGPoint(x: 0, y: self.bounds.height / 2))
path.addLine(to: CGPoint(x: self.bounds.maxX, y: 0))
path.addLine(to: CGPoint(x: self.bounds.maxX, y: self.bounds.maxY))
path.addLine(to: CGPoint(x: 0, y: self.bounds.height / 2))
path.close()
self.drawColor(color: .green)
self.backgroundColor = .clear
}
func drawColor(color: UIColor) {
print("TriangleView drawColor")
color.setFill()
path.lineWidth = 0
path.fill()
path.stroke()
}
}
In this code, TriangleView draws a triangle filled with green color.
After that, ViewController changes filled color by yellow.
Following the result.
There are two problems.
Background color is black though expectation is clear.
Triangle color is not changed to yellow.
Could anyone give me advice ?
Use UIGraphicsGetCurrentContext
class TriangleView: UIView {
private var triangleColor: UIColor = .green {
didSet {
self.setNeedsDisplay()
}
}
override func draw(_ rect: CGRect) {
print("TriangleView draw")
self.backgroundColor = .white // Set any background color
guard let context = UIGraphicsGetCurrentContext() else { return }
context.saveGState()
defer { context.restoreGState() }
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: self.bounds.height / 2))
path.addLine(to: CGPoint(x: self.bounds.maxX, y: 0))
path.addLine(to: CGPoint(x: self.bounds.maxX, y: self.bounds.maxY))
path.addLine(to: CGPoint(x: 0, y: self.bounds.height / 2))
path.close()
context.addPath(path.cgPath)
context.setFillColor(triangleColor.cgColor)
context.closePath()
context.closePath()
context.fillPath()
context.restoreGState()
}
func drawColor(color: UIColor) {
triangleColor = color
}
}
Or you can use CAShapeLayer
class TriangleView: UIView {
private let shapeLayer = CAShapeLayer()
override init(frame: CGRect) {
super.init(frame: frame)
self.initialConfig()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.initialConfig()
}
override func draw(_ rect: CGRect) {
print("TriangleView draw")
self.shapeLayer.frame = self.bounds
drawShape()
}
private func initialConfig() {
self.backgroundColor = .white
self.shapeLayer.fillColor = UIColor.green.cgColor
self.layer.addSublayer(shapeLayer)
}
private func drawShape() {
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: self.bounds.height / 2))
path.addLine(to: CGPoint(x: self.bounds.maxX, y: 0))
path.addLine(to: CGPoint(x: self.bounds.maxX, y: self.bounds.maxY))
path.addLine(to: CGPoint(x: 0, y: self.bounds.height / 2))
path.close()
shapeLayer.path = path.cgPath
}
func drawColor(color: UIColor) {
self.shapeLayer.fillColor = color.cgColor
}
}
I drawed triangle but I can't see on storyboard. How can I see on storyboard this drawing ?
View Controller Code:
class ViewController: UIViewController {
#IBOutlet weak var fooView: UIView!
var polygonShape = CAShapeLayer()
override func viewDidLoad() {
super.viewDidLoad()
let polygonPath = UIBezierPath()
polygonPath.move(to: CGPoint(x: 50, y: -1))
polygonPath.addLine(to: CGPoint(x: 93.3, y: 74))
polygonPath.addLine(to: CGPoint(x: 6.7, y: 74))
polygonPath.close()
polygonShape.frame = fooView.bounds
polygonShape.path = polygonPath.cgPath
fooView.layer.mask = polygonShape
}
}
Change your class to this:
#IBDesignable
class FirstImageView: UIView {
var polygonShape: CAShapeLayer!
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
if polygonShape == nil {
polygonShape = CAShapeLayer()
layer.mask = polygonShape
}
}
override func layoutSubviews() {
super.layoutSubviews()
let polygonPath = UIBezierPath()
polygonPath.move(to: CGPoint(x: 0.0, y: bounds.size.height))
polygonPath.addLine(to: CGPoint(x: bounds.width * 0.5, y: 0.0))
polygonPath.addLine(to: CGPoint(x: bounds.size.width, y: bounds.size.height))
polygonPath.close()
polygonShape.path = polygonPath.cgPath
}
}
You can remove everything from your ViewController class. You don't even need the class at all at this point.
Select the view on your Storyboard, and at the top of the Identity Inspector pane change the Custom Class from the default UIView to FirstImageView.
Under the top Editor menu, either select Refresh All Views or make sure Automatically Refresh Views is checked.
Result:
i want to add curve in my UIView as shown in image.
How can i create such uiview?
You can use UIBezierPath and use addCurve method to create your view.
//1. Create this new Class
class ComplexView: UIView {
var path: UIBezierPath!
override init(frame: CGRect) {
super.init(frame: frame)
self.alpha = 0.3
complexShape()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func draw(_ rect: CGRect) {
// Specify the fill color and apply it to the path.
UIColor.blue.setFill()
path.fill()
// Specify a border (stroke) color.
UIColor.magenta.setStroke()
path.stroke()
}
func complexShape() {
path = UIBezierPath()
path.move(to: CGPoint(x: 0.0, y: 0.0))
path.addCurve(to: CGPoint(x: 0, y: self.frame.size.height),
controlPoint1: CGPoint(x: 50.0, y: 25.0),
controlPoint2: CGPoint(x: 50.0, y: self.frame.size.height - 25.0))
path.close()
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
self.backgroundColor = UIColor.orange
self.layer.mask = shapeLayer
}
}
In your ViewController call this View and add this view to your main view.
//2. In you Viewcontoller add ComplexView
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let width: CGFloat = 100.0
let height: CGFloat = 500.0
let complexView = ComplexView(frame: CGRect(x: 0,
y: self.view.frame.size.height/2 - height/2,
width: width,
height: height))
self.view.addSubview(complexView)
}
You need to play around addCurve method to get your desired shape.
I have to draw a shape and detect if user touches are inside the shape or not, so I defined a custom class inherit from UIView as follow :
class ShapeView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ rect: CGRect) {
drawShape()
}
func drawShape() {
guard let ctx = UIGraphicsGetCurrentContext() else { return }
let zero = CGPoint(x: frame.midX, y: frame.midY)
let size: CGFloat = 50
ctx.beginPath()
ctx.move(to: .zero)
ctx.addLine(to: CGPoint(x: -size, y: -size))
ctx.addLine(to: CGPoint(x: zero.x , y: (-size * 2)))
ctx.addLine(to: CGPoint(x: size, y: -size))
ctx.closePath()
ctx.setFillColor(UIColor.red.cgColor)
ctx.fillPath()
}
this code should draw shape like this
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
let path = UIBezierPath(ovalIn: self.frame)
return path.contains(point)
}
}
and in the viewController I wrote this code to add this custom view to UIViewController :
var shape: ShapeView?
override func viewDidLoad() {
super.viewDidLoad()
let x = view.frame.midX
let y = view.frame.midY
self.shape = ShapeView(frame: CGRect(x: x, y: y, width: 100, height: 100))
shape?.backgroundColor = .green
view.addSubview(shape!)
}
I knew that the shape is inside the view after wrote this method :
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let location = touches.first!.location(in: self.view)
if (shape?.point(inside: location, with: event))! {
print("inside view")
} else {
print("outside view")
}
but overall result was this image it just has one color of the view as green and there's a subview but no color appeared
So what's wrong with this code ?
You should use the size of the rect of the override func draw(_ rect: CGRect) to do your calculations on.
I also think your calculations are incorrect, haven't tested it but I think it should be something like this:
ctx.move(to: CGPoint(x: rect.width / 2, y: 0))
ctx.addLine(to: CGPoint(x: rect.width, y: rect.height / 2))
ctx.addLine(to: CGPoint(x: rect.width / 2 , y: rect.height))
ctx.addLine(to: CGPoint(x: 0, y: rect.height / 2))
Do I have to create a custom class in order to use the BezierPath in the Swift playgrounds?
The following code displays nothing but black background:
import UIKit
import XCPlayground
class GraphView : UIView {
override func drawRect(rect: CGRect) {
let path = UIBezierPath(rect: rect)
path.moveToPoint(CGPointMake(0,0))
path.addLineToPoint(CGPointMake(50,100))
path.closePath()
UIColor.redColor().setFill()
path.stroke()
}
}
let graphView = GraphView(frame: CGRectMake(0,0,960,640))
You have to use this at the end of your code:
XCPlaygroundPage.currentPage.liveView = graphView
and to open the Playground's "Assistant Editor" to see the result.
And also to change the background color of the view since it's black... and your line is also black. ;)
In Swift 5:
import UIKit
class GraphView : UIView {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .white
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ rect: CGRect) {
let path = UIBezierPath(rect: rect)
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: 50, y: 100))
path.stroke()
}
}
let graphView = GraphView(frame: CGRect(x: 0, y: 0, width: 960, height: 640))
Swift 5.2, Xcode 11.4