how to draw tic tac toe board as UIView in swift? - swift

In my UIViewController I have a single subclass of UIView in which I will draw a tic tac toe board. Somehow the dividers (the "#" shape) I'm drawing using UIBezierPath() are not dividing the board evenly. Instead of 1/3-1/3-1/3, the vertical dividers are closer to 45%-45%-10% even though the dimensions printouts make sense. What am I missing? Thanks
In my subclass:
import UIKit
#IBDesignable class GameBoardView: UIView {
override func drawRect(rect: CGRect) {
// set up gameBoard dimensions everytime drawRect() is called
setUpGameBoardCells()
self.frame = CGRectMake(gameBoardPosX, gameBoardPosY, gameBoardLength, gameBoardLength)
print("gameBoard.frame: x=\(self.frame.origin.x), y=\(self.frame.origin.y), h=\(self.frame.height), w=\(self.frame.width)\n")
// draw dividers & cells
var divider = UIBezierPath(rect: CGRect(x: cellWidth, y: 0, width: dividerWidth, height: gameBoardLength))
divider.lineWidth = 1
UIColor.orangeColor().setStroke()
divider.stroke()
divider = UIBezierPath(rect: CGRect(x: cellWidth * 2 + dividerWidth, y: 0, width: dividerWidth, height: gameBoardLength))
divider.stroke()
}
}
And this is how I set up the dimensions to handle any sized screens:
var screenSize = CGRect()
let screenMargin: CGFloat = 20 // to the edge
var gameBoardIsPortrait = Bool()
var gameBoardLength = CGFloat()
var gameBoardPosX = CGFloat()
var gameBoardPosY = CGFloat()
let cellsPerRow: Int = 3
var cellWidth = CGFloat()
let dividerWidthGuide: CGFloat = 0.02 // guideline % of gameBoardLength
var dividerWidth = CGFloat()
let debugPrint = true
func setUpGameBoardCells() {
screenSize = UIScreen.mainScreen().bounds
// gameBoard is a square
gameBoardIsPortrait = (screenSize.height >= screenSize.width ? true : false)
gameBoardLength = min(screenSize.height, screenSize.width) - screenMargin * 2
gameBoardPosX = (screenSize.width - gameBoardLength) / 2
gameBoardPosY = (screenSize.height - gameBoardLength) / 2
// want cells & dividers on gameBoard to be whole numbers
dividerWidth = round(gameBoardLength * dividerWidthGuide)
let cellsTotalWidth: Int = Int(gameBoardLength) - Int(dividerWidth) * (cellsPerRow - 1)
let dividerWidthFudge: CGFloat = (cellsTotalWidth % cellsPerRow == 1 ? -1 : (cellsTotalWidth % cellsPerRow == 2 ? 1 : 0))
dividerWidth += dividerWidthFudge
cellWidth = CGFloat((cellsTotalWidth - Int(dividerWidthFudge) * (cellsPerRow - 1)) / cellsPerRow)
if debugPrint {
print("setUpCellDivision()->\nscreen: h=\(screenSize.height), w=\(screenSize.width)")
print("gameBoardIsPortrait=\(gameBoardIsPortrait), gameBoardLength=\(gameBoardLength), gameBoardPosX=\(gameBoardPosX), gameBoardPosY=\(gameBoardPosY)")
print("cellWidth=\(cellWidth), dividerWidth=\(dividerWidth)\n")
}
}
What is bizarre is that in xcode it looks right:
But in simulator it looks like this:

The problem is the setting of the frame from within drawRect. This would especially be a problem if you have any auto-layout constraints defined for the view.
The laying out of a view and the drawing of that view are two different steps, and you should therefore separate that logic.
Personally, I'd set up auto-layout constraints on the view to make sure that it is square, centered, and had the correct spacing. Then the view rendering is simplified:
#IBDesignable class GameBoardView: UIView {
override func drawRect(rect: CGRect) {
setUpGameBoardCells()
UIColor.orangeColor().setStroke()
var divider = UIBezierPath(rect: CGRect(x: cellWidth, y: 0, width: dividerWidth, height: bounds.size.height))
divider.lineWidth = 1
divider.stroke()
divider = UIBezierPath(rect: CGRect(x: cellWidth * 2 + dividerWidth, y: 0, width: dividerWidth, height: bounds.size.height))
divider.lineWidth = 1
divider.stroke()
}
let cellsPerRow = 3
let dividerWidthGuide: CGFloat = 0.02 // guideline % of gameBoardLength
var cellWidth: CGFloat!
var cellHeight: CGFloat!
var dividerWidth: CGFloat!
func setUpGameBoardCells() {
let gameBoardLength = min(bounds.size.height, bounds.size.width)
dividerWidth = round(gameBoardLength * dividerWidthGuide)
let cellsTotalWidth: Int = Int(gameBoardLength) - Int(dividerWidth) * (cellsPerRow - 1)
let dividerWidthFudge: CGFloat = (cellsTotalWidth % cellsPerRow == 1 ? -1 : (cellsTotalWidth % cellsPerRow == 2 ? 1 : 0))
dividerWidth! += dividerWidthFudge
cellWidth = CGFloat((cellsTotalWidth - Int(dividerWidthFudge) * (cellsPerRow - 1)) / cellsPerRow)
}
}
That yields:
Clearly, just repeat for your horizontal separators, too.

The simplest way would be adding UIViews(as separator lines) on yellow UIView and constraint them properly. You don't have to write too much of code.I would suggest to avoid the code in such cases.
You can try this. Draw the lines by calculating the frame of the view. The following will resize according to the frame.
func drawRect(frame frame: CGRect = CGRect(x: 52, y: 30, width: 90, height: 75)) {
//// Bezier Drawing
let bezierPath = UIBezierPath()
UIColor.blackColor().setStroke()
bezierPath.lineWidth = 1
bezierPath.stroke()
//// Rectangle Drawing
let rectanglePath = UIBezierPath(rect: CGRect(x: frame.minX + floor(frame.width * 0.32778) + 0.5, y: frame.minY + floor(frame.height * 0.06000) + 0.5, width: floor(frame.width * 0.35000) - floor(frame.width * 0.32778), height: floor(frame.height * 0.92667) - floor(frame.height * 0.06000)))
UIColor.blackColor().setStroke()
rectanglePath.lineWidth = 1
rectanglePath.stroke()
//// Rectangle 3 Drawing
let rectangle3Path = UIBezierPath(rect: CGRect(x: frame.minX + floor(frame.width * 0.68333) + 0.5, y: frame.minY + floor(frame.height * 0.06000) + 0.5, width: floor(frame.width * 0.70556) - floor(frame.width * 0.68333), height: floor(frame.height * 0.92667) - floor(frame.height * 0.06000)))
UIColor.blackColor().setStroke()
rectangle3Path.lineWidth = 1
rectangle3Path.stroke()
//// Rectangle 5 Drawing
let rectangle5Path = UIBezierPath(rect: CGRect(x: frame.minX + floor(frame.width * 0.07222) + 0.5, y: frame.minY + floor(frame.height * 0.63333) + 0.5, width: floor(frame.width * 0.92778) - floor(frame.width * 0.07222), height: floor(frame.height * 0.66000) - floor(frame.height * 0.63333)))
UIColor.blackColor().setStroke()
rectangle5Path.lineWidth = 1
rectangle5Path.stroke()
//// Rectangle 6 Drawing
let rectangle6Path = UIBezierPath(rect: CGRect(x: frame.minX + floor(frame.width * 0.07222) + 0.5, y: frame.minY + floor(frame.height * 0.31333) + 0.5, width: floor(frame.width * 0.92778) - floor(frame.width * 0.07222), height: floor(frame.height * 0.34000) - floor(frame.height * 0.31333)))
UIColor.blackColor().setStroke()
rectangle6Path.lineWidth = 1
rectangle6Path.stroke()
}

It seems as if your constraints aren't set up correctly. Try redoing the constraints to see if that fixes things.

Related

How to round corners of this custom shape SwiftUI?

I used this tutorial to create a hexagon shape:
https://www.hackingwithswift.com/quick-start/swiftui/how-to-draw-polygons-and-stars
My goal is to try to round the corners of my hexagon shape. I know I have to use the path.addCurve somehow, but I cannot figure out where I need to do that. I am only getting weird results. Has anyone got an idea?
struct Polygon: Shape {
let corners: Int
let smoothness: CGFloat
func path(in rect: CGRect) -> Path {
guard corners >= 2 else { return Path() }
let center = CGPoint(x: rect.width / 2, y: rect.height / 2)
var currentAngle = -CGFloat.pi / 2
let angleAdjustment = .pi * 2 / CGFloat(corners * 2)
let innerX = center.x * smoothness
let innerY = center.y * smoothness
var path = Path()
path.move(to: CGPoint(x: center.x * cos(currentAngle), y: center.y * sin(currentAngle)))
var bottomEdge: CGFloat = 0
for corner in 0 ..< corners * 2 {
let sinAngle = sin(currentAngle)
let cosAngle = cos(currentAngle)
let bottom: CGFloat
if corner.isMultiple(of: 2) {
bottom = center.y * sinAngle
path.addLine(to: CGPoint(x: center.x * cosAngle, y: bottom))
} else {
bottom = innerY * sinAngle
path.addLine(to: CGPoint(x: innerX * cosAngle, y: bottom))
}
if bottom > bottomEdge {
bottomEdge = bottom
}
currentAngle += angleAdjustment
}
let unusedSpace = (rect.height / 2 - bottomEdge) / 2
let transform = CGAffineTransform(translationX: center.x, y: center.y + unusedSpace)
return path.applying(transform)
}
}
struct Hexagon: View {
#Environment(\.colorScheme) var colorScheme
var body: some View {
Polygon(corners: 3, smoothness: 1)
.fill(.clear)
.frame(width: 76, height: 76)
}
}
Haven't found a fix but this library does what I want:
https://github.com/heestand-xyz/PolyKit

How can l set frames for 12 buttons with loop (programatically)?

I'm trying to make Concentration game (with matching cards) and my task is to set frames for the array of 12 UIButtons with for-loop (I tried to realize it with switches, but it wan't right as my mentor said).
So maybe you can help me with this. The code added below works correctly, but l have to escape of switch and make it works with the help of for-loop and universal formulas.
func setFrames() {
for i in 0...11{
var x = CGFloat()
var y = CGFloat()
switch i {
case 0...2:
y = 50
case 3...5:
y = (7/36 * view.bounds.height + 50);
case 6...8:
y = (7/18 * view.bounds.height + 50);
default:
y = (7/12 * view.bounds.height + 50);
}
switch i {
case 0, 3, 6, 9:
x = 1/18 * view.bounds.width; //20
case 1, 4, 7, 10:
x = 3/8 * view.bounds.width; //3/8
default:
x = 3/4 * view.bounds.width - 20;
}
buttonsArray[i].frame = CGRect(x: x, y: y, width: (1/4 * view.bounds.width), height: (1/6 * view.bounds.height))
}
}
You can use something like so:
func placeBtnsIn(frame: CGRect, padding: CGFloat) {
let numCols = 3
let numRows = 4
let buttonWidth = (frame.width - CGFloat(numCols - 1) * padding) / CGFloat(numCols)
let buttonHeight = (frame.height - CGFloat(numRows - 1) * padding) / CGFloat(numRows)
var x: CGFloat
var y: CGFloat
for row in 0...(numRows - 1) {
y = frame.origin.y + (buttonHeight + padding) * CGFloat(row)
for col in 0...(numCols - 1) {
x = frame.origin.x + (buttonWidth + padding) * CGFloat(col)
let button = UIButton()
button.frame = CGRect(x: x, y: y, width: buttonWidth, height: buttonHeight)
self.addSubview(button)
}
}
}
Then in your code use it like so:
placeBtnsIn(frame: yourFrame, padding: 5)
Where yourFrame is a rectangle in which buttons should be drawn, and padding is the distance between button "cells"

Create a centered and rotated UILabels, between drawn lines in Core Graphic

I have the following code, to draw a circle, with segments inside of it :
override func draw(_ rect: CGRect) {
super.draw(rect)
if let context = UIGraphicsGetCurrentContext()
{
let width = fmin(self.frame.size.width, self.frame.size.height)
let offset_x = abs(width - self.frame.size.width)/2
let offset_y = abs(width - self.frame.size.height)/2
let padding = CGFloat(0.5)
let radius_size = (width/2) - (padding*2)
let circle_width = radius_size/4
context.setStrokeColor(UIColor.black.cgColor)
// Draw a circle
for i in 0 ..< 4
{
let offset = CGFloat(i) * circle_width
context.strokeEllipse(in:
CGRect(
x: padding + offset + offset_x,
y: padding + offset + offset_y,
width: (radius_size - offset)*2,
height: (radius_size - offset)*2))
}
let angles: [CGFloat] = [87.0, 112.0, 150]
let angles2: [CGFloat] = [210.0, 250.0, 330.0]
let center = CGPoint(x: width/2 + offset_x, y: width/2 + offset_y)
for angle in angles {
drawLine(context: context, center: center, radius: radius_size, angle: angle)
}
for angle in angles2 {
drawLine(context: context, center: center, radius: radius_size * 3 / 4, angle: angle)
}
context.strokePath()
}
}
func drawLine(context: CGContext, center: CGPoint, radius: CGFloat, angle: CGFloat) {
context.move(to: center)
context.addLine(to: CGPoint(x: center.x + radius * cos(angle * .pi / 180), y: center.y - radius * sin(angle * .pi / 180)))
}
I want to be able, to create a centered between the segments UILabels, with rotation to the right angle, I made an example in photo editor:
Thanks in advance.
I found the answer:
func drawCurvedText(angle: CGFloat, text: String) {
drawCurvedString(
on: textView.layer,
text: NSAttributedString(
string: text,
attributes: [
NSAttributedString.Key.foregroundColor: UIColor.white,
NSAttributedString.Key.font: UIFont.systemFont(ofSize: 15)
]),
angle: -angle,
radius: 130)
}
func drawCurvedString(on layer: CALayer, text: NSAttributedString, angle: CGFloat, radius: CGFloat) {
var radAngle = angle.radians
let textSize = text.boundingRect(
with: CGSize(width: .max, height: .max),
options: [.usesLineFragmentOrigin, .usesFontLeading],
context: nil)
.integral
.size
let perimeter: CGFloat = 2 * .pi * radius
let textAngle: CGFloat = textSize.width / perimeter * 2 * .pi
var textRotation: CGFloat = 0
var textDirection: CGFloat = 0
if angle > CGFloat(10).radians, angle < CGFloat(170).radians {
// bottom string
textRotation = 0.5 * .pi
textDirection = -2 * .pi
radAngle += textAngle / 2
} else {
// top string
textRotation = 1.5 * .pi
textDirection = 2 * .pi
radAngle -= textAngle / 2
}
for c in 0..<text.length {
let letter = text.attributedSubstring(from: NSRange(c..<c+1))
let charSize = letter.boundingRect(
with: CGSize(width: .max, height: .max),
options: [.usesLineFragmentOrigin, .usesFontLeading],
context: nil)
.integral
.size
let letterAngle = (charSize.width / perimeter) * textDirection
let x = radius * cos(radAngle + (letterAngle / 2))
let y = radius * sin(radAngle + (letterAngle / 2))
let singleChar = drawText(
on: layer,
text: letter,
frame: CGRect(
x: (layer.frame.size.width / 2) - (charSize.width / 2) + x,
y: (layer.frame.size.height / 2) - (charSize.height / 2) + y,
width: charSize.width,
height: charSize.height))
layer.addSublayer(singleChar)
singleChar.transform = CATransform3DMakeAffineTransform(CGAffineTransform(rotationAngle: radAngle - textRotation))
radAngle += letterAngle
}
}
func drawText(on layer: CALayer, text: NSAttributedString, frame: CGRect) -> CATextLayer {
let textLayer = CATextLayer()
textLayer.frame = frame
textLayer.string = text
textLayer.alignmentMode = CATextLayerAlignmentMode.center
textLayer.contentsScale = UIScreen.main.scale
return textLayer
}

How to generate UIImages in a hexagon "map" view

I'm building an app where I want to display profilePictures of people "near you" in a hexagon beehive style.
The full beehive should be draggable, like google maps for example.
My question is if this is something I can do with just using UIKit, or if it would be easier to use UIKit and SpriteKit together.
I hope someone could point me at the right direction and or have some ideas on how this could be made. Thank you for your time!
Update:
Just to make my question a bit more clear.
This is how my view looks like atm
And this is what I want to achieve
In the first image I´ve just set the X and Y pos of the UIImage center middle.
I want to create some sort of function that can get an array of different profilePics and then put the out in this pattern.
UIKit alone can do the job: you should try to setup a mask with CALayer on a UIImageView for instance.
The draggable behavior thing can be achieved either with a UIScrollView by adding and arranging all your image subviews in it, or with a UICollectionView with a custom flow, but it may be much harder to set up.
For the hexagon views, you'll find here an interesting example you can adapt for your usage: http://sapandiwakar.in/make-hexagonal-view-on-ios/
Here is an adaption of Sapan Diwakar solution in Swift 4.2 and using extensions:
extension UIBezierPath {
convenience init(roundedPolygonPathInRect rect: CGRect, lineWidth: CGFloat, sides: NSInteger, cornerRadius: CGFloat = 0, rotationOffset: CGFloat = 0) {
self.init()
let theta: CGFloat = 2.0 * CGFloat.pi / CGFloat(sides) // How much to turn at every corner
let width = min(rect.size.width, rect.size.height) // Width of the square
let center = CGPoint(x: rect.origin.x + width / 2.0, y: rect.origin.y + width / 2.0)
// Radius of the circle that encircles the polygon
// Notice that the radius is adjusted for the corners, that way the largest outer
// dimension of the resulting shape is always exactly the width - linewidth
let radius = (width - lineWidth + cornerRadius - (cos(theta) * cornerRadius)) / 2.0
// Start drawing at a point, which by default is at the right hand edge
// but can be offset
var angle = CGFloat(rotationOffset)
let corner = CGPoint(x: center.x + (radius - cornerRadius) * cos(angle), y: center.y + (radius - cornerRadius) * sin(angle))
move(to: CGPoint(x: corner.x + cornerRadius * cos(angle + theta), y: corner.y + cornerRadius * sin(angle + theta)))
for _ in 0 ..< sides {
angle += theta
let corner = CGPoint(x: center.x + (radius - cornerRadius) * cos(angle), y: center.y + (radius - cornerRadius) * sin(angle))
let tip = CGPoint(x: center.x + radius * cos(angle), y: center.y + radius * sin(angle))
let start = CGPoint(x: corner.x + cornerRadius * cos(angle - theta), y: corner.y + cornerRadius * sin(angle - theta))
let end = CGPoint(x: corner.x + cornerRadius * cos(angle + theta), y: corner.y + cornerRadius * sin(angle + theta))
addLine(to: start)
addQuadCurve(to: end, controlPoint: tip)
}
close()
}
}
extension UIImageView {
func setupHexagonMask(lineWidth: CGFloat, color: UIColor, cornerRadius: CGFloat) {
let path = UIBezierPath(roundedPolygonPathInRect: bounds, lineWidth: lineWidth, sides: 6, cornerRadius: cornerRadius, rotationOffset: CGFloat.pi / 2.0).cgPath
let mask = CAShapeLayer()
mask.path = path
mask.lineWidth = lineWidth
mask.strokeColor = UIColor.clear.cgColor
mask.fillColor = UIColor.white.cgColor
layer.mask = mask
let border = CAShapeLayer()
border.path = path
border.lineWidth = lineWidth
border.strokeColor = color.cgColor
border.fillColor = UIColor.clear.cgColor
layer.addSublayer(border)
}
}
And then you can just use it like that:
let image = UIImageView(frame: CGRect(x: 30, y: 30, width: 300, height: 300))
image.contentMode = .scaleAspectFill
image.image = UIImage(named: "lenna.png")
image.setupHexagonMask(lineWidth: 5.0, color: .white, cornerRadius: 20.0)
view.addSubview(image)
EDIT: As I told you, the easiest way is to use a UIScrollView to display your map, and with simple math you can display your hexagons the way you want.
Here is a small example you must adapt to match your requirements. For example you should be extra careful with performance. This example should not be used as is, if you have many images, you should load them on the fly and remove them when you don't show them. And you can even think using a background rendering if it takes too much fps...
Assuming view is a UIScrollView:
let hexaDiameter : CGFloat = 150
let hexaWidth = hexaDiameter * sqrt(3) * 0.5
let hexaWidthDelta = (hexaDiameter - hexaWidth) * 0.5
let hexaHeightDelta = hexaDiameter * 0.25
let spacing : CGFloat = 5
let rows = 10
let firstRowColumns = 6
view.contentSize = CGSize(width: spacing + CGFloat(firstRowColumns) * (hexaWidth + spacing),
height: spacing + CGFloat(rows) * (hexaDiameter - hexaHeightDelta + spacing) + hexaHeightDelta)
for y in 0..<rows {
let cellsInRow = y % 2 == 0 ? firstRowColumns : firstRowColumns - 1
let rowXDelta = y % 2 == 0 ? 0.0 : (hexaWidth + spacing) * 0.5
for x in 0..<cellsInRow {
let image = UIImageView(frame: CGRect(x: rowXDelta + CGFloat(x) * (hexaWidth + spacing) + spacing - hexaWidthDelta,
y: CGFloat(y) * (hexaDiameter - hexaHeightDelta + spacing) + spacing,
width: hexaDiameter,
height: hexaDiameter))
image.contentMode = .scaleAspectFill
image.image = UIImage(named: "lenna.png")
image.setupHexagonMask(lineWidth: 5.0, color: .white, cornerRadius: 10.0)
view.addSubview(image)
}
}

Drawing hexagon image using Swift 4

public func roundedPolygonPath(rect: CGRect, lineWidth: CGFloat, sides: NSInteger, cornerRadius: CGFloat, rotationOffset: CGFloat = 0) -> UIBezierPath {
let path = UIBezierPath()
let theta: CGFloat = CGFloat(2.0 * M_PI) / CGFloat(sides) // How much to turn at every corner
let offset: CGFloat = cornerRadius * tan(theta / 2.0) // Offset from which to start rounding corners
let width = min(rect.size.width, rect.size.height) // Width of the square
let center = CGPoint(x: rect.origin.x + width / 2.0, y: rect.origin.y + width / 2.0)
// Radius of the circle that encircles the polygon
// Notice that the radius is adjusted for the corners, that way the largest outer
// dimension of the resulting shape is always exactly the width - linewidth
let radius = (width - lineWidth + cornerRadius - (cos(theta) * cornerRadius)) / 2.0
// Start drawing at a point, which by default is at the right hand edge
// but can be offset
var angle = CGFloat(rotationOffset)
let corner = CGPoint(x: center.x + (radius - cornerRadius) * cos(angle),y: center.y + (radius - cornerRadius) * sin(angle))
path.move(to: CGPoint(x: corner.x + cornerRadius * cos(angle + theta),y: corner.y + cornerRadius * sin(angle + theta)))
for _ in 0..<sides {
angle += theta
let corner = CGPoint(x: center.x + (radius - cornerRadius) * cos(angle),y: center.y + (radius - cornerRadius) * sin(angle))
let tip = CGPoint(x: center.x + radius * cos(angle),y: center.y + radius * sin(angle))
let start = CGPoint(x: corner.x + cornerRadius * cos(angle - theta),y: corner.y + cornerRadius * sin(angle - theta))
let end = CGPoint(x: corner.x + cornerRadius * cos(angle + theta), y: corner.y + cornerRadius * sin(angle + theta))
path.addLine(to: start)
path.addQuadCurve(to: end, controlPoint: tip)
}
path.close()
// Move the path to the correct origins
let bounds = path.bounds
let transform = CGAffineTransform(translationX: -bounds.origin.x + rect.origin.x + lineWidth / 2.0, y: -bounds.origin.y + rect.origin.y + lineWidth / 2.0)
path.apply(transform)
return path
}
public func createImage(layer: CALayer) -> UIImage {
let size = CGSizeMake(CGRect.maxX(layer.frame), CGRect.maxY(layer.frame))
UIGraphicsBeginImageContextWithOptions(size, layer.isOpaque, 0.0)
let ctx = UIGraphicsGetCurrentContext()
layer.render(in: ctx!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
let lineWidth = CGFloat(7.0)
let rect = CGRectMake(0.0, 0.0, 150.0, 150.0)
let sides = 6
var path = roundedPolygonPath(rect, lineWidth, sides, 15.0, rotationOffset: CGFloat(-M_PI / 2.0))
let borderLayer = CAShapeLayer()
borderLayer.frame = CGRectMake(0.0, 0.0, path.bounds.width + lineWidth, path.bounds.height + lineWidth)
borderLayer.path = path.CGPath
borderLayer.lineWidth = lineWidth
borderLayer.lineJoin = kCALineJoinRound
borderLayer.lineCap = kCALineCapRound
borderLayer.strokeColor = UIColor.blackColor().CGColor
borderLayer.fillColor = UIColor.whiteColor().CGColor
var image = createImage(borderLayer)}[enter image description here][1]
I cannot convert the Swift 3 with CGRect and CGSizeMake functions to latest Swift 4.
The following errors is due to the conversion of Swift 3 example. I have found,
'CGRectMake' is unavailable in Swift
Extensions may not contain stored properties
'CGSizeMake' is unavailable in Swift
*Im trying to draw the path **
Instead of CGSizeMake you now can use CGSize.init, e.g. CGSize(width: 100, height: 50).
Instead of the static function CGRect.maxX you now can use the member method of the same name: CGRect.maxX(layer.frame) becomes layer.frame.maxX.