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
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
Swift 3 Objc Optional Protocol Method Not Called in Subclass
How to Use Swift Repl with iOS Sdk
Removing Badge from iOS App Icon
Xcode 7.1 Swift 2 Unknown Class in Interface Builder File
How to Generate PDF File from a Xml/HTML Template in iOS
Alternatives to Weak Linking in iPhone Sdk
Will iOS Wake Up the Terminated App If It's Registered with Location for Uibackgroundmodes
Uicollectionview Scrolling in Both Directions
Ios: Differencebetween -Init and -Viewload of a Viewcontroller
What Does It Mean to "Weak-Link" a Framework
How to Tell If Your Code Is Running on an iPhone or an Iphone3G
Nsurlconnection Deprecated in iOS9
Using Collectionview in Uiview with Xib File
How to Create and Send the JSON Data to Server Using Swift Language
How to Create a Release Build in Xcode
Wanted: How to Reliably, Consistently Select an Mkmapview Annotation