admin管理员组文章数量:1391925
I'm trying to create a circular text path in SwiftUI using a custom CircularTextPath view. The text is being drawn on an arc, and I want to add a background color behind the path, as shown in another image I have (for example, adding a solid background color to the entire text arc).
CircularTextPath:
import SwiftUI
struct CircularTextPath: View {
let text: String
let arcAngle: Angle
var body: some View {
if arcAngle.radians != 0.0 {
textAsPath
.fixedSize()
.hidden()
.overlay {
GeometryReader { fullText in
let textWidth = fullText.size.width
let startAngle = -(arcAngle.radians / 2)
let radius = arcAngle.radians > 0 ? textWidth * 1.5 / arcAngle.radians : textWidth * 2.0 / arcAngle.radians
HStack(spacing: 0) {
ForEach(Array(text.enumerated()), id: \.offset) { index, character in
Text(String(character))
.hidden()
.overlay {
GeometryReader { charSpace in
let midX = charSpace.frame(in: .named("FullText")).midX
let fraction = midX / textWidth
let angle = startAngle + (fraction * arcAngle.radians)
let xOffset = (textWidth / 2) - midX
TextPath(character: String(character))
.scaleEffect(x: 1, y: 1) // Flip horizontally to correct mirroring
.offset(y: -radius)
.rotationEffect(.radians(angle))
.offset(x: xOffset, y: radius)
}
}
}
}
.fixedSize()
.frame(width: textWidth)
}
}
.coordinateSpace(name: "FullText")
} else {
textAsPath
}
}
private var textAsPath: some View {
HStack(spacing: 0) {
ForEach(Array(text.enumerated()), id: \.offset) { index, character in
TextPath(character: String(character))
.scaleEffect(x: 1, y: 1) // Flip horizontally to correct mirroring
}
}
}
}
struct TextPath: View {
let character: String
var body: some View {
let path = characterToPath(character)
return path.fill(Color.primary)
}
private func characterToPath(_ character: String) -> Path {
let font = UIFont.systemFont(ofSize: 20)
let attributedString = NSAttributedString(string: character, attributes: [.font: font])
let line = CTLineCreateWithAttributedString(attributedString)
let path = CGMutablePath()
for run in (CTLineGetGlyphRuns(line) as! [CTRun]) {
for index in 0..<CTRunGetGlyphCount(run) {
var glyph = CGGlyph()
var position = CGPoint()
CTRunGetGlyphs(run, CFRangeMake(index, 1), &glyph)
CTRunGetPositions(run, CFRangeMake(index, 1), &position)
if let letterPath = CTFontCreatePathForGlyph(font, glyph, nil) {
let transform = CGAffineTransform(translationX: position.x, y: position.y).scaledBy(x: 1, y: -1) // Flip horizontally
path.addPath(letterPath, transform: transform)
}
}
}
return Path(path)
}
}
What I want to achieve: I want to add a background color behind the path, specifically behind the entire circular arc of text. How can I modify this code to add a solid background color to the path, similar to the effect shown in the other image I have?
What I've tried so far:
- I’ve tried using .background(Color) or .overlay(Color) to add a background to the - - - TextPath, but these don’t seem to achieve the desired effect.
- I’ve also tried adding a background color to the path itself, but that didn’t work out because the path isn't a solid object, it's just the outline of the text.
what output I got
output I want
what I want to do
when two or three lines
I'm trying to create a circular text path in SwiftUI using a custom CircularTextPath view. The text is being drawn on an arc, and I want to add a background color behind the path, as shown in another image I have (for example, adding a solid background color to the entire text arc).
CircularTextPath:
import SwiftUI
struct CircularTextPath: View {
let text: String
let arcAngle: Angle
var body: some View {
if arcAngle.radians != 0.0 {
textAsPath
.fixedSize()
.hidden()
.overlay {
GeometryReader { fullText in
let textWidth = fullText.size.width
let startAngle = -(arcAngle.radians / 2)
let radius = arcAngle.radians > 0 ? textWidth * 1.5 / arcAngle.radians : textWidth * 2.0 / arcAngle.radians
HStack(spacing: 0) {
ForEach(Array(text.enumerated()), id: \.offset) { index, character in
Text(String(character))
.hidden()
.overlay {
GeometryReader { charSpace in
let midX = charSpace.frame(in: .named("FullText")).midX
let fraction = midX / textWidth
let angle = startAngle + (fraction * arcAngle.radians)
let xOffset = (textWidth / 2) - midX
TextPath(character: String(character))
.scaleEffect(x: 1, y: 1) // Flip horizontally to correct mirroring
.offset(y: -radius)
.rotationEffect(.radians(angle))
.offset(x: xOffset, y: radius)
}
}
}
}
.fixedSize()
.frame(width: textWidth)
}
}
.coordinateSpace(name: "FullText")
} else {
textAsPath
}
}
private var textAsPath: some View {
HStack(spacing: 0) {
ForEach(Array(text.enumerated()), id: \.offset) { index, character in
TextPath(character: String(character))
.scaleEffect(x: 1, y: 1) // Flip horizontally to correct mirroring
}
}
}
}
struct TextPath: View {
let character: String
var body: some View {
let path = characterToPath(character)
return path.fill(Color.primary)
}
private func characterToPath(_ character: String) -> Path {
let font = UIFont.systemFont(ofSize: 20)
let attributedString = NSAttributedString(string: character, attributes: [.font: font])
let line = CTLineCreateWithAttributedString(attributedString)
let path = CGMutablePath()
for run in (CTLineGetGlyphRuns(line) as! [CTRun]) {
for index in 0..<CTRunGetGlyphCount(run) {
var glyph = CGGlyph()
var position = CGPoint()
CTRunGetGlyphs(run, CFRangeMake(index, 1), &glyph)
CTRunGetPositions(run, CFRangeMake(index, 1), &position)
if let letterPath = CTFontCreatePathForGlyph(font, glyph, nil) {
let transform = CGAffineTransform(translationX: position.x, y: position.y).scaledBy(x: 1, y: -1) // Flip horizontally
path.addPath(letterPath, transform: transform)
}
}
}
return Path(path)
}
}
What I want to achieve: I want to add a background color behind the path, specifically behind the entire circular arc of text. How can I modify this code to add a solid background color to the path, similar to the effect shown in the other image I have?
What I've tried so far:
- I’ve tried using .background(Color) or .overlay(Color) to add a background to the - - - TextPath, but these don’t seem to achieve the desired effect.
- I’ve also tried adding a background color to the path itself, but that didn’t work out because the path isn't a solid object, it's just the outline of the text.
what output I got
output I want
what I want to do
when two or three lines
Share Improve this question edited Mar 13 at 5:00 HeWhoRemains asked Mar 12 at 11:52 HeWhoRemainsHeWhoRemains 6511 bronze badges 5- I only know cgPath of that text , that is Path – HeWhoRemains Commented Mar 12 at 12:04
- can you write a simple demo , what are you saying – HeWhoRemains Commented Mar 12 at 12:08
- I used that way but I need result in Path so I just converted it to path – HeWhoRemains Commented Mar 12 at 12:18
- Let us continue this discussion in chat. – HeWhoRemains Commented Mar 12 at 12:36
- Let us continue this discussion in chat. – HeWhoRemains Commented Mar 12 at 12:37
1 Answer
Reset to default 2Converting a path that contains the outline of letters to an arc may be difficult. However, maybe there is an easier way.
If you know the arc angle and the radius then you can simply trim the path of a circle. Your example includes these values, so you should be able to stroke the trimmed circle without having to convert the text to a path.
Here is an example to show it working. I am using CurvedText
for this, as I was suggesting you use in my answer to your earlier question.
let arcDegrees: Double = 320
let radius: CGFloat = 90
let fontSize: CGFloat = 50
let strokeWidth: CGFloat = 70
var body: some View {
ZStack {
let endTrimFraction = (360.0 - arcDegrees) / (2 * 360.0)
Circle()
.trim(from: endTrimFraction, to: 1 - endTrimFraction)
.stroke(.black, lineWidth: strokeWidth)
.rotationEffect(.degrees(-90))
.padding(fontSize / 2)
// See https://stackoverflow/a/77280669/20386264
CurvedText(string: "I am he who remains", radius: -radius)
.offset(y: radius)
.font(.system(size: fontSize, weight: .black))
.foregroundStyle(.white)
}
.frame(width: (2 * radius) + fontSize, height: (2 * radius) + fontSize)
}
EDIT If I understand correctly, what you are aiming for is a way to vary the arc angle of some text dynamically, exactly as was being done in your earlier question, but also to show a colored background behind the text. The background should fit the text as the angle is changed.
So, based on the approach shown above, here is an adaption of the answer I previously provided to your other question. The main changes:
- The view
CircularText
now accepts a binding to a variable which is used to record the computed radius (4 lines of code added, no other changes). - The parent view
CircularTextView
displays the background behind the curved text.
I found that it looks best if the background is slightly wider than the text. The easiest way to achieve this is to add leading and trailing spaces to the text being shown.
struct CircularTextView: View {
@State private var arcDegrees: Double = 0
@State private var textRadius = CGFloat.zero
let text: String = " I am he who remains " //
本文标签:
版权声明:本文标题:ios - How to add a background color to a path, similar to the one shown in another image? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人,
转载请联系作者并注明出处:http://www.betaflare.com/web/1744754434a2623375.html,
本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论