Swift: UIBezierPath fill intersection of 2 paths
I'm working with 2 UIBezierPath
to create a rectangle and a semicircle shape. It works fine but I am not able to fill the intersection with color.
That's my drawCircle
and my addPaths
functions:
private func drawCircle(selectedPosition: SelectionRangePosition, currentMonth: Bool) {
circleView.layer.sublayers = nil
let radius = contentView.bounds.height/2
let arcCenter = CGPoint(x: ceil(contentView.bounds.width/2), y: ceil(contentView.bounds.height/2))
let circlePath = UIBezierPath(arcCenter: arcCenter, radius: radius, startAngle: .pi/2, endAngle: .pi * 3/2, clockwise: selectedPosition == .left)
let semiCircleLayerPath = UIBezierPath()
let semiCircleLayer = CAShapeLayer()
semiCircleLayer.fillColor = UIColor.tealish.cgColor
circleView.layer.addSublayer(semiCircleLayer)
switch (selectedPosition, currentMonth) {
case (.left, true):
let rectanglePath = UIBezierPath(rect: CGRect(x: contentView.bounds.width / 2, y: 0, width: ceil(contentView.bounds.width / 2), height: contentView.bounds.height))
addPaths(semiCircleLayerPath, rectanglePath, circlePath, semiCircleLayer)
case (.middle, true):
backgroundColor = .tealish
case (.right, true):
// Note: The + 10 is just to overlap the shapes and test if the filling works
let rectanglePath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: ceil(contentView.bounds.width / 2) + 10, height: contentView.bounds.height))
addPaths(semiCircleLayerPath, rectanglePath, circlePath, semiCircleLayer)
default:
backgroundColor = .clear
}
}
private func addPaths(_ semiCircleLayerPath: UIBezierPath, _ rectanglePath: UIBezierPath, _ circlePath: UIBezierPath, _ semiCircleLayer: CAShapeLayer) {
semiCircleLayerPath.append(circlePath)
semiCircleLayerPath.append(rectanglePath)
semiCircleLayer.path = semiCircleLayerPath.cgPath
}
ios swift
add a comment |
I'm working with 2 UIBezierPath
to create a rectangle and a semicircle shape. It works fine but I am not able to fill the intersection with color.
That's my drawCircle
and my addPaths
functions:
private func drawCircle(selectedPosition: SelectionRangePosition, currentMonth: Bool) {
circleView.layer.sublayers = nil
let radius = contentView.bounds.height/2
let arcCenter = CGPoint(x: ceil(contentView.bounds.width/2), y: ceil(contentView.bounds.height/2))
let circlePath = UIBezierPath(arcCenter: arcCenter, radius: radius, startAngle: .pi/2, endAngle: .pi * 3/2, clockwise: selectedPosition == .left)
let semiCircleLayerPath = UIBezierPath()
let semiCircleLayer = CAShapeLayer()
semiCircleLayer.fillColor = UIColor.tealish.cgColor
circleView.layer.addSublayer(semiCircleLayer)
switch (selectedPosition, currentMonth) {
case (.left, true):
let rectanglePath = UIBezierPath(rect: CGRect(x: contentView.bounds.width / 2, y: 0, width: ceil(contentView.bounds.width / 2), height: contentView.bounds.height))
addPaths(semiCircleLayerPath, rectanglePath, circlePath, semiCircleLayer)
case (.middle, true):
backgroundColor = .tealish
case (.right, true):
// Note: The + 10 is just to overlap the shapes and test if the filling works
let rectanglePath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: ceil(contentView.bounds.width / 2) + 10, height: contentView.bounds.height))
addPaths(semiCircleLayerPath, rectanglePath, circlePath, semiCircleLayer)
default:
backgroundColor = .clear
}
}
private func addPaths(_ semiCircleLayerPath: UIBezierPath, _ rectanglePath: UIBezierPath, _ circlePath: UIBezierPath, _ semiCircleLayer: CAShapeLayer) {
semiCircleLayerPath.append(circlePath)
semiCircleLayerPath.append(rectanglePath)
semiCircleLayer.path = semiCircleLayerPath.cgPath
}
ios swift
It's the even / odd fill rule at work here. Try settingpath.usesEvenOddFillRule = true
.
– JonJ
Nov 21 '18 at 16:07
I setsemiCircleLayerPath.usesEvenOddFillRule = true
but it doesn't make any difference. I tried alsosemiCircleLayerPath.fill()
.
– gmoraleda
Nov 21 '18 at 16:09
1
Best way is to draw a single path with the relevant corner radii, then you avoid overlapping paths.
– JonJ
Nov 21 '18 at 16:13
add a comment |
I'm working with 2 UIBezierPath
to create a rectangle and a semicircle shape. It works fine but I am not able to fill the intersection with color.
That's my drawCircle
and my addPaths
functions:
private func drawCircle(selectedPosition: SelectionRangePosition, currentMonth: Bool) {
circleView.layer.sublayers = nil
let radius = contentView.bounds.height/2
let arcCenter = CGPoint(x: ceil(contentView.bounds.width/2), y: ceil(contentView.bounds.height/2))
let circlePath = UIBezierPath(arcCenter: arcCenter, radius: radius, startAngle: .pi/2, endAngle: .pi * 3/2, clockwise: selectedPosition == .left)
let semiCircleLayerPath = UIBezierPath()
let semiCircleLayer = CAShapeLayer()
semiCircleLayer.fillColor = UIColor.tealish.cgColor
circleView.layer.addSublayer(semiCircleLayer)
switch (selectedPosition, currentMonth) {
case (.left, true):
let rectanglePath = UIBezierPath(rect: CGRect(x: contentView.bounds.width / 2, y: 0, width: ceil(contentView.bounds.width / 2), height: contentView.bounds.height))
addPaths(semiCircleLayerPath, rectanglePath, circlePath, semiCircleLayer)
case (.middle, true):
backgroundColor = .tealish
case (.right, true):
// Note: The + 10 is just to overlap the shapes and test if the filling works
let rectanglePath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: ceil(contentView.bounds.width / 2) + 10, height: contentView.bounds.height))
addPaths(semiCircleLayerPath, rectanglePath, circlePath, semiCircleLayer)
default:
backgroundColor = .clear
}
}
private func addPaths(_ semiCircleLayerPath: UIBezierPath, _ rectanglePath: UIBezierPath, _ circlePath: UIBezierPath, _ semiCircleLayer: CAShapeLayer) {
semiCircleLayerPath.append(circlePath)
semiCircleLayerPath.append(rectanglePath)
semiCircleLayer.path = semiCircleLayerPath.cgPath
}
ios swift
I'm working with 2 UIBezierPath
to create a rectangle and a semicircle shape. It works fine but I am not able to fill the intersection with color.
That's my drawCircle
and my addPaths
functions:
private func drawCircle(selectedPosition: SelectionRangePosition, currentMonth: Bool) {
circleView.layer.sublayers = nil
let radius = contentView.bounds.height/2
let arcCenter = CGPoint(x: ceil(contentView.bounds.width/2), y: ceil(contentView.bounds.height/2))
let circlePath = UIBezierPath(arcCenter: arcCenter, radius: radius, startAngle: .pi/2, endAngle: .pi * 3/2, clockwise: selectedPosition == .left)
let semiCircleLayerPath = UIBezierPath()
let semiCircleLayer = CAShapeLayer()
semiCircleLayer.fillColor = UIColor.tealish.cgColor
circleView.layer.addSublayer(semiCircleLayer)
switch (selectedPosition, currentMonth) {
case (.left, true):
let rectanglePath = UIBezierPath(rect: CGRect(x: contentView.bounds.width / 2, y: 0, width: ceil(contentView.bounds.width / 2), height: contentView.bounds.height))
addPaths(semiCircleLayerPath, rectanglePath, circlePath, semiCircleLayer)
case (.middle, true):
backgroundColor = .tealish
case (.right, true):
// Note: The + 10 is just to overlap the shapes and test if the filling works
let rectanglePath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: ceil(contentView.bounds.width / 2) + 10, height: contentView.bounds.height))
addPaths(semiCircleLayerPath, rectanglePath, circlePath, semiCircleLayer)
default:
backgroundColor = .clear
}
}
private func addPaths(_ semiCircleLayerPath: UIBezierPath, _ rectanglePath: UIBezierPath, _ circlePath: UIBezierPath, _ semiCircleLayer: CAShapeLayer) {
semiCircleLayerPath.append(circlePath)
semiCircleLayerPath.append(rectanglePath)
semiCircleLayer.path = semiCircleLayerPath.cgPath
}
ios swift
ios swift
edited Nov 21 '18 at 16:01
gmoraleda
asked Nov 21 '18 at 15:54


gmoraledagmoraleda
437416
437416
It's the even / odd fill rule at work here. Try settingpath.usesEvenOddFillRule = true
.
– JonJ
Nov 21 '18 at 16:07
I setsemiCircleLayerPath.usesEvenOddFillRule = true
but it doesn't make any difference. I tried alsosemiCircleLayerPath.fill()
.
– gmoraleda
Nov 21 '18 at 16:09
1
Best way is to draw a single path with the relevant corner radii, then you avoid overlapping paths.
– JonJ
Nov 21 '18 at 16:13
add a comment |
It's the even / odd fill rule at work here. Try settingpath.usesEvenOddFillRule = true
.
– JonJ
Nov 21 '18 at 16:07
I setsemiCircleLayerPath.usesEvenOddFillRule = true
but it doesn't make any difference. I tried alsosemiCircleLayerPath.fill()
.
– gmoraleda
Nov 21 '18 at 16:09
1
Best way is to draw a single path with the relevant corner radii, then you avoid overlapping paths.
– JonJ
Nov 21 '18 at 16:13
It's the even / odd fill rule at work here. Try setting
path.usesEvenOddFillRule = true
.– JonJ
Nov 21 '18 at 16:07
It's the even / odd fill rule at work here. Try setting
path.usesEvenOddFillRule = true
.– JonJ
Nov 21 '18 at 16:07
I set
semiCircleLayerPath.usesEvenOddFillRule = true
but it doesn't make any difference. I tried also semiCircleLayerPath.fill()
.– gmoraleda
Nov 21 '18 at 16:09
I set
semiCircleLayerPath.usesEvenOddFillRule = true
but it doesn't make any difference. I tried also semiCircleLayerPath.fill()
.– gmoraleda
Nov 21 '18 at 16:09
1
1
Best way is to draw a single path with the relevant corner radii, then you avoid overlapping paths.
– JonJ
Nov 21 '18 at 16:13
Best way is to draw a single path with the relevant corner radii, then you avoid overlapping paths.
– JonJ
Nov 21 '18 at 16:13
add a comment |
2 Answers
2
active
oldest
votes
The problem is that the semicircle path and the rectangle path are being added in opposite directions. This is a function of the way the Cocoa API adds them, unfortunately; in your case, it means that the intersection has a "wrap count" of 0.
Fortunately, there is an easy fix: create separate paths for the semicircle and the rectangle. When fill them both individually, you should get your desired result.
Unfortunately, this will mean that you can't use layer drawing only: you will want to use the drawRect method to draw the background.
add a comment |
If your dates are separate UILabels, you can skip this rendering & path filling problem entirely by dropping a UIView as a child of the calendar, under the labels holding the dates; give it a background color & rounded corners (using layer.cornerRadius
as usual). That'll take care of your rounded rect for you.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53415870%2fswift-uibezierpath-fill-intersection-of-2-paths%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
The problem is that the semicircle path and the rectangle path are being added in opposite directions. This is a function of the way the Cocoa API adds them, unfortunately; in your case, it means that the intersection has a "wrap count" of 0.
Fortunately, there is an easy fix: create separate paths for the semicircle and the rectangle. When fill them both individually, you should get your desired result.
Unfortunately, this will mean that you can't use layer drawing only: you will want to use the drawRect method to draw the background.
add a comment |
The problem is that the semicircle path and the rectangle path are being added in opposite directions. This is a function of the way the Cocoa API adds them, unfortunately; in your case, it means that the intersection has a "wrap count" of 0.
Fortunately, there is an easy fix: create separate paths for the semicircle and the rectangle. When fill them both individually, you should get your desired result.
Unfortunately, this will mean that you can't use layer drawing only: you will want to use the drawRect method to draw the background.
add a comment |
The problem is that the semicircle path and the rectangle path are being added in opposite directions. This is a function of the way the Cocoa API adds them, unfortunately; in your case, it means that the intersection has a "wrap count" of 0.
Fortunately, there is an easy fix: create separate paths for the semicircle and the rectangle. When fill them both individually, you should get your desired result.
Unfortunately, this will mean that you can't use layer drawing only: you will want to use the drawRect method to draw the background.
The problem is that the semicircle path and the rectangle path are being added in opposite directions. This is a function of the way the Cocoa API adds them, unfortunately; in your case, it means that the intersection has a "wrap count" of 0.
Fortunately, there is an easy fix: create separate paths for the semicircle and the rectangle. When fill them both individually, you should get your desired result.
Unfortunately, this will mean that you can't use layer drawing only: you will want to use the drawRect method to draw the background.
answered Nov 21 '18 at 16:11
Tim KokeshTim Kokesh
70457
70457
add a comment |
add a comment |
If your dates are separate UILabels, you can skip this rendering & path filling problem entirely by dropping a UIView as a child of the calendar, under the labels holding the dates; give it a background color & rounded corners (using layer.cornerRadius
as usual). That'll take care of your rounded rect for you.
add a comment |
If your dates are separate UILabels, you can skip this rendering & path filling problem entirely by dropping a UIView as a child of the calendar, under the labels holding the dates; give it a background color & rounded corners (using layer.cornerRadius
as usual). That'll take care of your rounded rect for you.
add a comment |
If your dates are separate UILabels, you can skip this rendering & path filling problem entirely by dropping a UIView as a child of the calendar, under the labels holding the dates; give it a background color & rounded corners (using layer.cornerRadius
as usual). That'll take care of your rounded rect for you.
If your dates are separate UILabels, you can skip this rendering & path filling problem entirely by dropping a UIView as a child of the calendar, under the labels holding the dates; give it a background color & rounded corners (using layer.cornerRadius
as usual). That'll take care of your rounded rect for you.
answered Nov 21 '18 at 16:51
Graham PerksGraham Perks
17.1k64671
17.1k64671
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53415870%2fswift-uibezierpath-fill-intersection-of-2-paths%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
It's the even / odd fill rule at work here. Try setting
path.usesEvenOddFillRule = true
.– JonJ
Nov 21 '18 at 16:07
I set
semiCircleLayerPath.usesEvenOddFillRule = true
but it doesn't make any difference. I tried alsosemiCircleLayerPath.fill()
.– gmoraleda
Nov 21 '18 at 16:09
1
Best way is to draw a single path with the relevant corner radii, then you avoid overlapping paths.
– JonJ
Nov 21 '18 at 16:13