Reputation: 547
I am working with BezierPath and could make a basic star shape within a view successfully, it works great. However, the view's size can be changeable. And I cannot center this bezier path when the view size is changed, I managed to scale it but getting center was hard to me.
private func pointFrom(_ angle: CGFloat, radius: CGFloat, offset: CGPoint) -> CGPoint {
return CGPoint(x: radius * cos(angle) + offset.x, y: radius * sin(angle) + offset.y)//CGPointMake(radius * cos(angle) + offset.x, radius * sin(angle) + offset.y)
}
private func generateStar(width:CGFloat, height:CGFloat, radius:CGFloat) -> CAShapeLayer{
let path = UIBezierPath()
var scale = width / height
if width > height{
scale = height / width
}
let starExtrusion:CGFloat = 60.0
let center = CGPoint(x: width / 2.0, y: height / 2.0)
let pointsOnStar = 5
var angle:CGFloat = -CGFloat(.pi / 2.0)
let angleIncrement = CGFloat(.pi * 2.0 / Double(pointsOnStar))
let radius = width / 2.0
var firstPoint = true
for _ in 1...pointsOnStar {
let point = pointFrom(angle, radius: radius, offset: center)
let nextPoint = pointFrom(angle + angleIncrement, radius: radius, offset: center)
let midPoint = pointFrom(angle + angleIncrement / 2.0, radius: starExtrusion, offset: center)
if firstPoint {
firstPoint = false
path.move(to: point)
}
path.addLine(to: midPoint)//addLineToPoint(midPoint)
path.addLine(to: nextPoint)//addLineToPoint(nextPoint)
angle += angleIncrement
}
path.apply(CGAffineTransform(scaleX: scale, y: scale))
path.close()
let maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath
return maskLayer
}
How can I manage to make that? Thanks!
Upvotes: 0
Views: 1396
Reputation: 154563
The center of your path moves with this command:
path.apply(CGAffineTransform(scaleX: scale, y: scale))
To keep your center
in the center, scale it by 1 / scale
so that when it is scaled by scale
, it will end up in the center of the view (since (1 / scale) * scale == 1
):
Change:
let center = CGPoint(x: width / 2.0, y: height / 2.0)
to:
let center = CGPoint(x: width / 2.0 / scale, y: height / 2.0 / scale)
The two scalings cancel each other and the center of the path then ends up where it was originally calculated to be.
That said, you are shrinking your star when height != width
. You might get a better result if you forget about the scaling and just choose the minimum of width
and height
for your radius
calculation:
Get rid of scale
, or set it to 1.0
, then
Change:
let radius = width / 2.0
to:
let radius = min(width, height) / 2.0
That will let the star be as large as possible while still fitting fully within the view.
As you noticed, the star gets "fat" (more circular) as it gets smaller. This is because you have a hard-coded constant of 60.0
for starExtrusion
. That value should be based upon the radius
.
Set starExtrusion
after calculating radius
:
let radius = min(width, height) / 2.0
let starExtrusion = radius * 0.4
You can vary the 0.4
multiplier to alter the shape of the star.
Upvotes: 2
Reputation: 8845
UIView's layoutSubviews
got called when resized, you can reset the mask by overriding that method.
Upvotes: 1