How do I draw stuff under the text of a UILabel?
I created a custom UILabel
subclass that has a circle in the middle, and the label's text (which is a number) will be on top of the circle.
I initially thought of doing this using layer.cornerRadius
, but that will not create a circle when the label's width and height are not equal.
What I mean is, for a label with width 100 and height 50, I still want a circle with radius 50 and centre at (50, 25).
Therefore, I tried to use UIBezierPath
to draw the circle. This is what I have tried:
override func draw(_ rect: CGRect) {
super.draw(rect)
if bounds.height > bounds.width {
let y = (bounds.height - bounds.width) / 2
let path = UIBezierPath(ovalIn: CGRect(x: 0, y: y, width: bounds.width, height: bounds.width))
circleColor.setFill()
path.fill()
} else {
let x = (bounds.width - bounds.height) / 2
let path = UIBezierPath(ovalIn: CGRect(x: x, y: 0, width: bounds.height, height: bounds.height))
circleColor.setFill()
path.fill()
}
}
I have put super.draw(rect)
because I thought that would draw the label's text, but when I run the app, I only see the circle and not my label text.
I am very confused because why hasn't super.draw(rect)
drawn the label's text?
ios swift uiview uibezierpath
add a comment |
I created a custom UILabel
subclass that has a circle in the middle, and the label's text (which is a number) will be on top of the circle.
I initially thought of doing this using layer.cornerRadius
, but that will not create a circle when the label's width and height are not equal.
What I mean is, for a label with width 100 and height 50, I still want a circle with radius 50 and centre at (50, 25).
Therefore, I tried to use UIBezierPath
to draw the circle. This is what I have tried:
override func draw(_ rect: CGRect) {
super.draw(rect)
if bounds.height > bounds.width {
let y = (bounds.height - bounds.width) / 2
let path = UIBezierPath(ovalIn: CGRect(x: 0, y: y, width: bounds.width, height: bounds.width))
circleColor.setFill()
path.fill()
} else {
let x = (bounds.width - bounds.height) / 2
let path = UIBezierPath(ovalIn: CGRect(x: x, y: 0, width: bounds.height, height: bounds.height))
circleColor.setFill()
path.fill()
}
}
I have put super.draw(rect)
because I thought that would draw the label's text, but when I run the app, I only see the circle and not my label text.
I am very confused because why hasn't super.draw(rect)
drawn the label's text?
ios swift uiview uibezierpath
When drawing/painting, think in the context of a physical canvas, those things you paint will be covered by those things you paint/draw later
– MadProgrammer
Jan 3 at 2:29
add a comment |
I created a custom UILabel
subclass that has a circle in the middle, and the label's text (which is a number) will be on top of the circle.
I initially thought of doing this using layer.cornerRadius
, but that will not create a circle when the label's width and height are not equal.
What I mean is, for a label with width 100 and height 50, I still want a circle with radius 50 and centre at (50, 25).
Therefore, I tried to use UIBezierPath
to draw the circle. This is what I have tried:
override func draw(_ rect: CGRect) {
super.draw(rect)
if bounds.height > bounds.width {
let y = (bounds.height - bounds.width) / 2
let path = UIBezierPath(ovalIn: CGRect(x: 0, y: y, width: bounds.width, height: bounds.width))
circleColor.setFill()
path.fill()
} else {
let x = (bounds.width - bounds.height) / 2
let path = UIBezierPath(ovalIn: CGRect(x: x, y: 0, width: bounds.height, height: bounds.height))
circleColor.setFill()
path.fill()
}
}
I have put super.draw(rect)
because I thought that would draw the label's text, but when I run the app, I only see the circle and not my label text.
I am very confused because why hasn't super.draw(rect)
drawn the label's text?
ios swift uiview uibezierpath
I created a custom UILabel
subclass that has a circle in the middle, and the label's text (which is a number) will be on top of the circle.
I initially thought of doing this using layer.cornerRadius
, but that will not create a circle when the label's width and height are not equal.
What I mean is, for a label with width 100 and height 50, I still want a circle with radius 50 and centre at (50, 25).
Therefore, I tried to use UIBezierPath
to draw the circle. This is what I have tried:
override func draw(_ rect: CGRect) {
super.draw(rect)
if bounds.height > bounds.width {
let y = (bounds.height - bounds.width) / 2
let path = UIBezierPath(ovalIn: CGRect(x: 0, y: y, width: bounds.width, height: bounds.width))
circleColor.setFill()
path.fill()
} else {
let x = (bounds.width - bounds.height) / 2
let path = UIBezierPath(ovalIn: CGRect(x: x, y: 0, width: bounds.height, height: bounds.height))
circleColor.setFill()
path.fill()
}
}
I have put super.draw(rect)
because I thought that would draw the label's text, but when I run the app, I only see the circle and not my label text.
I am very confused because why hasn't super.draw(rect)
drawn the label's text?
ios swift uiview uibezierpath
ios swift uiview uibezierpath
asked Jan 3 at 1:51
SweeperSweeper
70.5k1075143
70.5k1075143
When drawing/painting, think in the context of a physical canvas, those things you paint will be covered by those things you paint/draw later
– MadProgrammer
Jan 3 at 2:29
add a comment |
When drawing/painting, think in the context of a physical canvas, those things you paint will be covered by those things you paint/draw later
– MadProgrammer
Jan 3 at 2:29
When drawing/painting, think in the context of a physical canvas, those things you paint will be covered by those things you paint/draw later
– MadProgrammer
Jan 3 at 2:29
When drawing/painting, think in the context of a physical canvas, those things you paint will be covered by those things you paint/draw later
– MadProgrammer
Jan 3 at 2:29
add a comment |
1 Answer
1
active
oldest
votes
The text is not seen because the "z-index" of UIBezierPath
s depends on the order in which they are drawn. In other words, UIBezierPath
s are drawn on top of each other.
super.draw(rect)
indeed draws the text. But when you put it as the first statement, it will get drawn first, so everything you draw after that, goes on top of the text. To fix this, you should call super.draw(rect)
last:
override func draw(_ rect: CGRect) {
if bounds.height > bounds.width {
let y = (bounds.height - bounds.width) / 2
let path = UIBezierPath(ovalIn: CGRect(x: 0, y: y, width: bounds.width, height: bounds.width))
circleColor.setFill()
path.fill()
} else {
let x = (bounds.width - bounds.height) / 2
let path = UIBezierPath(ovalIn: CGRect(x: x, y: 0, width: bounds.height, height: bounds.height))
circleColor.setFill()
path.fill()
}
super.draw(rect) // <------- here!
}
Alternatively, just subclass UIView
, draw the circle in draw(_:)
, and add a UILabel
as a subview of that. The advantage if this approach is that it does not depend on the implementation of super.draw(_:)
, which might change in the future,
Instead of subclassing the UILabel, why not just create a custom view with the UILabel on top, and leave the drawing code in the custom view?
– meim
Jan 3 at 5:31
@meim I want to make it using as few subviews as possible, because I don't want to add that many constraints on each of them.
– Sweeper
Jan 3 at 5:45
With this implementation, it's possible in the future your custom drawing code is overwritten by super.draw(rect) since it's a black box inside UILabel's implementation. In the custom view implementation, if you're worried about too many constraints, you can simply set label.frame = bounds in layoutSubviews
– meim
Jan 3 at 6:02
@meim Oh I see. You do have a point. Edited.
– Sweeper
Jan 3 at 6:07
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%2f54015404%2fhow-do-i-draw-stuff-under-the-text-of-a-uilabel%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
The text is not seen because the "z-index" of UIBezierPath
s depends on the order in which they are drawn. In other words, UIBezierPath
s are drawn on top of each other.
super.draw(rect)
indeed draws the text. But when you put it as the first statement, it will get drawn first, so everything you draw after that, goes on top of the text. To fix this, you should call super.draw(rect)
last:
override func draw(_ rect: CGRect) {
if bounds.height > bounds.width {
let y = (bounds.height - bounds.width) / 2
let path = UIBezierPath(ovalIn: CGRect(x: 0, y: y, width: bounds.width, height: bounds.width))
circleColor.setFill()
path.fill()
} else {
let x = (bounds.width - bounds.height) / 2
let path = UIBezierPath(ovalIn: CGRect(x: x, y: 0, width: bounds.height, height: bounds.height))
circleColor.setFill()
path.fill()
}
super.draw(rect) // <------- here!
}
Alternatively, just subclass UIView
, draw the circle in draw(_:)
, and add a UILabel
as a subview of that. The advantage if this approach is that it does not depend on the implementation of super.draw(_:)
, which might change in the future,
Instead of subclassing the UILabel, why not just create a custom view with the UILabel on top, and leave the drawing code in the custom view?
– meim
Jan 3 at 5:31
@meim I want to make it using as few subviews as possible, because I don't want to add that many constraints on each of them.
– Sweeper
Jan 3 at 5:45
With this implementation, it's possible in the future your custom drawing code is overwritten by super.draw(rect) since it's a black box inside UILabel's implementation. In the custom view implementation, if you're worried about too many constraints, you can simply set label.frame = bounds in layoutSubviews
– meim
Jan 3 at 6:02
@meim Oh I see. You do have a point. Edited.
– Sweeper
Jan 3 at 6:07
add a comment |
The text is not seen because the "z-index" of UIBezierPath
s depends on the order in which they are drawn. In other words, UIBezierPath
s are drawn on top of each other.
super.draw(rect)
indeed draws the text. But when you put it as the first statement, it will get drawn first, so everything you draw after that, goes on top of the text. To fix this, you should call super.draw(rect)
last:
override func draw(_ rect: CGRect) {
if bounds.height > bounds.width {
let y = (bounds.height - bounds.width) / 2
let path = UIBezierPath(ovalIn: CGRect(x: 0, y: y, width: bounds.width, height: bounds.width))
circleColor.setFill()
path.fill()
} else {
let x = (bounds.width - bounds.height) / 2
let path = UIBezierPath(ovalIn: CGRect(x: x, y: 0, width: bounds.height, height: bounds.height))
circleColor.setFill()
path.fill()
}
super.draw(rect) // <------- here!
}
Alternatively, just subclass UIView
, draw the circle in draw(_:)
, and add a UILabel
as a subview of that. The advantage if this approach is that it does not depend on the implementation of super.draw(_:)
, which might change in the future,
Instead of subclassing the UILabel, why not just create a custom view with the UILabel on top, and leave the drawing code in the custom view?
– meim
Jan 3 at 5:31
@meim I want to make it using as few subviews as possible, because I don't want to add that many constraints on each of them.
– Sweeper
Jan 3 at 5:45
With this implementation, it's possible in the future your custom drawing code is overwritten by super.draw(rect) since it's a black box inside UILabel's implementation. In the custom view implementation, if you're worried about too many constraints, you can simply set label.frame = bounds in layoutSubviews
– meim
Jan 3 at 6:02
@meim Oh I see. You do have a point. Edited.
– Sweeper
Jan 3 at 6:07
add a comment |
The text is not seen because the "z-index" of UIBezierPath
s depends on the order in which they are drawn. In other words, UIBezierPath
s are drawn on top of each other.
super.draw(rect)
indeed draws the text. But when you put it as the first statement, it will get drawn first, so everything you draw after that, goes on top of the text. To fix this, you should call super.draw(rect)
last:
override func draw(_ rect: CGRect) {
if bounds.height > bounds.width {
let y = (bounds.height - bounds.width) / 2
let path = UIBezierPath(ovalIn: CGRect(x: 0, y: y, width: bounds.width, height: bounds.width))
circleColor.setFill()
path.fill()
} else {
let x = (bounds.width - bounds.height) / 2
let path = UIBezierPath(ovalIn: CGRect(x: x, y: 0, width: bounds.height, height: bounds.height))
circleColor.setFill()
path.fill()
}
super.draw(rect) // <------- here!
}
Alternatively, just subclass UIView
, draw the circle in draw(_:)
, and add a UILabel
as a subview of that. The advantage if this approach is that it does not depend on the implementation of super.draw(_:)
, which might change in the future,
The text is not seen because the "z-index" of UIBezierPath
s depends on the order in which they are drawn. In other words, UIBezierPath
s are drawn on top of each other.
super.draw(rect)
indeed draws the text. But when you put it as the first statement, it will get drawn first, so everything you draw after that, goes on top of the text. To fix this, you should call super.draw(rect)
last:
override func draw(_ rect: CGRect) {
if bounds.height > bounds.width {
let y = (bounds.height - bounds.width) / 2
let path = UIBezierPath(ovalIn: CGRect(x: 0, y: y, width: bounds.width, height: bounds.width))
circleColor.setFill()
path.fill()
} else {
let x = (bounds.width - bounds.height) / 2
let path = UIBezierPath(ovalIn: CGRect(x: x, y: 0, width: bounds.height, height: bounds.height))
circleColor.setFill()
path.fill()
}
super.draw(rect) // <------- here!
}
Alternatively, just subclass UIView
, draw the circle in draw(_:)
, and add a UILabel
as a subview of that. The advantage if this approach is that it does not depend on the implementation of super.draw(_:)
, which might change in the future,
edited Jan 3 at 6:07
answered Jan 3 at 1:51
SweeperSweeper
70.5k1075143
70.5k1075143
Instead of subclassing the UILabel, why not just create a custom view with the UILabel on top, and leave the drawing code in the custom view?
– meim
Jan 3 at 5:31
@meim I want to make it using as few subviews as possible, because I don't want to add that many constraints on each of them.
– Sweeper
Jan 3 at 5:45
With this implementation, it's possible in the future your custom drawing code is overwritten by super.draw(rect) since it's a black box inside UILabel's implementation. In the custom view implementation, if you're worried about too many constraints, you can simply set label.frame = bounds in layoutSubviews
– meim
Jan 3 at 6:02
@meim Oh I see. You do have a point. Edited.
– Sweeper
Jan 3 at 6:07
add a comment |
Instead of subclassing the UILabel, why not just create a custom view with the UILabel on top, and leave the drawing code in the custom view?
– meim
Jan 3 at 5:31
@meim I want to make it using as few subviews as possible, because I don't want to add that many constraints on each of them.
– Sweeper
Jan 3 at 5:45
With this implementation, it's possible in the future your custom drawing code is overwritten by super.draw(rect) since it's a black box inside UILabel's implementation. In the custom view implementation, if you're worried about too many constraints, you can simply set label.frame = bounds in layoutSubviews
– meim
Jan 3 at 6:02
@meim Oh I see. You do have a point. Edited.
– Sweeper
Jan 3 at 6:07
Instead of subclassing the UILabel, why not just create a custom view with the UILabel on top, and leave the drawing code in the custom view?
– meim
Jan 3 at 5:31
Instead of subclassing the UILabel, why not just create a custom view with the UILabel on top, and leave the drawing code in the custom view?
– meim
Jan 3 at 5:31
@meim I want to make it using as few subviews as possible, because I don't want to add that many constraints on each of them.
– Sweeper
Jan 3 at 5:45
@meim I want to make it using as few subviews as possible, because I don't want to add that many constraints on each of them.
– Sweeper
Jan 3 at 5:45
With this implementation, it's possible in the future your custom drawing code is overwritten by super.draw(rect) since it's a black box inside UILabel's implementation. In the custom view implementation, if you're worried about too many constraints, you can simply set label.frame = bounds in layoutSubviews
– meim
Jan 3 at 6:02
With this implementation, it's possible in the future your custom drawing code is overwritten by super.draw(rect) since it's a black box inside UILabel's implementation. In the custom view implementation, if you're worried about too many constraints, you can simply set label.frame = bounds in layoutSubviews
– meim
Jan 3 at 6:02
@meim Oh I see. You do have a point. Edited.
– Sweeper
Jan 3 at 6:07
@meim Oh I see. You do have a point. Edited.
– Sweeper
Jan 3 at 6:07
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%2f54015404%2fhow-do-i-draw-stuff-under-the-text-of-a-uilabel%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
When drawing/painting, think in the context of a physical canvas, those things you paint will be covered by those things you paint/draw later
– MadProgrammer
Jan 3 at 2:29