Triangle Uiview - Swift

Triangle UIView - Swift

Updated for Swift 3:

class TriangleView : 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.minX, y: rect.maxY))
context.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
context.addLine(to: CGPoint(x: (rect.maxX / 2.0), y: rect.minY))
context.closePath()

context.setFillColor(red: 1.0, green: 0.5, blue: 0.0, alpha: 0.60)
context.fillPath()
}
}


Swift 2:

import UIKit

class TriangleView : UIView {

override init(frame: CGRect) {
super.init(frame: frame)
}

required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}

override func drawRect(rect: CGRect) {

var ctx : CGContextRef = UIGraphicsGetCurrentContext()

CGContextBeginPath(ctx)
CGContextMoveToPoint(ctx, CGRectGetMinX(rect), CGRectGetMaxY(rect))
CGContextAddLineToPoint(ctx, CGRectGetMaxX(rect), CGRectGetMaxY(rect))
CGContextAddLineToPoint(ctx, (CGRectGetMaxX(rect)/2.0), CGRectGetMinY(rect))
CGContextClosePath(ctx)

CGContextSetRGBFillColor(ctx, 1.0, 0.5, 0.0, 0.60);
CGContextFillPath(ctx);
}
}

This will start from MinX, MaxY;

Draw a line from the start to MaxX, MaxY;

Draw a line from MaxX,MaxY to MaxX/2, MinY;

Then close the path to the start location.


The next part sets the color you want to use. In this example 255,127,0, Alpha 0.6
Then will fill the path you just drew above with the set color.

Then in your View Controller

Swift 3:

class ViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

let triangle = TriangleView(frame: CGRect(x: 10, y: 20, width: 25 , height: 30))
triangle.backgroundColor = .white
view.addSubview(triangle)
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}


Swift 2:

class ViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.

let triangle = TriangleView(frame: CGRectMake(10, 20, 25, 30))
triangle.backgroundColor = .whiteColor()
view.addSubview(triangle)
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

However, this is going to cause the same problem as the frame of this view is still going to be a rectangle. UIKit works with rectangles, you would have to use another framework, like Sprite Kit.

Creating Triangle with UIBezierPath in Swift

You just have the axes in your head upside down. The coordinate system starts at 0,0 and extends right in X and down in Y.

So your points are really:

           #2 x:50, y: 42.5 
#1 x:35, y:95 #3 x:65, y:95

to get your desired triangle you'd have something like:

 #1 x:35, y:95          #3 x:65, y:95
#2 x:50, y: 147.5

Making a triangle in a UIView with a CGRect Frame

There is tutorial here:

http://jamesonquave.com/blog/drawing-custom-views-with-swift-andrew-vanwagoner/

with code like this:

func drawPlayPathTo(context: CGContextRef, boundedBy rect: CGRect) {
CGContextSetFillColorWithColor(context, UIColor.blackColor().CGColor)
CGContextMoveToPoint(context, rect.width / 4, rect.height / 4)
CGContextAddLineToPoint(context, rect.width * 3 / 4, rect.height / 2)
CGContextAddLineToPoint(context, rect.width / 4, rect.height * 3 / 4)
CGContextAddLineToPoint(context, rect.width / 4, rect.height / 4)
CGContextFillPath(context)
}

Adding a triangular tip at the bottom of a rectangular UIView

You can try a UIImageView, then make sure when you import you enable the slicing, so if you change your view the image will scale properly.

Apparently you might be having an issue with UIView.clipsToBounds = true

If you want to use the drawing way, you can try this. I've coded in swift in the playground...

import UIKit

var balloon = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 250))
balloon.backgroundColor = UIColor.clear

let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: 200, y: 0))
path.addLine(to: CGPoint(x: 200, y: 200))

// Draw arrow
path.addLine(to: CGPoint(x: 120, y: 200))
path.addLine(to: CGPoint(x: 100, y: 250))
path.addLine(to: CGPoint(x: 80, y: 200))

path.addLine(to: CGPoint(x: 0, y: 200))
path.close()

let shape = CAShapeLayer()
//shape.backgroundColor = UIColor.blue.cgColor
shape.fillColor = UIColor.blue.cgColor
shape.path = path.cgPath
balloon.layer.addSublayer(shape)

balloon

example

Reference to use bezier path:
Ref

UIView mask triangle

You have most of the logic.

Think of having a pen drawing on a sheet of paper with coordinates.

 /\/\/\/\/\/\/\/\
| |
| |
| |
\/\/\/\/\/\/\/\/

So CGPoint.zero is top left and will be the start of our drawing.


+
/\/\/\/\/\/\/\/\
| |
| |
| |
\/\/\/\/\/\/\/\/

var point = CGPoint.zero
let path = UIBezierPath()
path.move(to: point)

So, let's draw the triangles.

----------------->
/\/\/\/\/\/\/\/\
| |
| |
| |
\/\/\/\/\/\/\/\/

var i = 0
var value = true
while Double(i) <= Double(width + 10) {
value.toggle()
point.x += constant
if value {
point.y -= constant
} else {
point.y += constant;
}
path.addLine(to: point)
i += 1
}

We are now at top right, so let's continue our drawing and let's go to bottom right:

 /\/\/\/\/\/\/\/\
| | |
| | |
| | |
\/\/\/\/\/\/\/\/ ˇ

point = CGPoint(x: width, y: height)
path.addLine(to: point)

Now, we need the triangles until reaching bottom left:

 /\/\/\/\/\/\/\/\
| |
| |
| |
\/\/\/\/\/\/\/\/
<-----------------

i = 0
value = true
while Double(i) <= Double(width + 10) {
value.toggle()
point.x -= constant
if value {
point.y += constant
} else {
point.y -= constant;
}
path.addLine(to: point)
i += 1
}

Now, let's go back to starting point and close:

^   /\/\/\/\/\/\/\/\
| | |
| | |
| | |
\/\/\/\/\/\/\/\/

point = CGPoint(x: 0, y: 0) //Not needed, but I find it cleaner to add it
path.addLine(to: point) //Not needed, but I find it cleaner to add it
path.close()

Side note, I factorize a little your loop, since you are doing repetitive command inside the if/else, I put them outside.

Creating Triangle Shaped Button with BezierUIView

First, you can directly create a subclass of UIButton and add create a shape.
Second, use a button frame rect to create a triangle, so the triangle is dynamic and dependent on the size and frame of the button.

Also, use .fill() for set background color to triangle.

Here, is the button subclass.

class TriangleButtonView: UIButton {

private let triangle = UIBezierPath()

override func draw(_ rect: CGRect) {
super.draw(rect)
triangle.move(to: CGPoint(x: 0, y: rect.height))
triangle.addLine(to: CGPoint(x:rect.width/2, y: 0))
triangle.addLine(to: CGPoint(x:rect.width, y:rect.height))
triangle.close()
UIColor.red.setFill() //<--- Fill your color here
triangle.fill()
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// This is for allow touches only in shape area.
if triangle.contains(touches.first?.location(in: self) ?? .zero) {
super.touchesBegan(touches, with: event)
// or you can use send action
// self.sendActions(for: .touchUpInside)
}
}
}

Your view controller,

class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let button = TriangleButtonView(frame: CGRect(x: 100, y: 100, width: 10, height: 10))
self.view.addSubview(button)
}
}

The problem in your code is, you are set triangle points more than the given frame from view controller class.

Shape a triangle with UIView backed by CAShapeLayer

Use this path instead:

CGPathMoveToPoint(path, nil, 0, 0)
CGPathAddLineToPoint(path, nil, width, 0)
CGPathAddLineToPoint(path, nil, width/2, height)
CGPathAddLineToPoint(path, nil, 0, 0)

full class:

class Triangle: UIView {
override func drawRect(rect: CGRect) {
let mask = CAShapeLayer()
mask.frame = self.layer.bounds

let width = self.layer.frame.size.width
let height = self.layer.frame.size.height

let path = CGPathCreateMutable()

CGPathMoveToPoint(path, nil, 0, 0)
CGPathAddLineToPoint(path, nil, width, 0)
CGPathAddLineToPoint(path, nil, width/2, height)
CGPathAddLineToPoint(path, nil, 0, 0)

mask.path = path
self.layer.mask = mask
}
}


Related Topics



Leave a reply



Submit