我有一个应用程序,我正在用一系列楔子创建一个圆,每个楔子都有一个类别标题,应该出现在楔子的顶部。我创建了楔形和一些弯曲的文本,这些文本应该位于圆圈的外边缘。然而,当我改变手机的大小时,文本会随着不同的比例移动。 所以我的问题是如何将文本锚定到圆圈上,以便无论手机大小如何都保持原位?
import SwiftUI
struct WedgeShape: Shape {
let startAngle: Angle
let endAngle: Angle
let lineWidth: CGFloat
func path(in rect: CGRect) -> Path {
var p = Path()
let center = CGPoint(x: rect.size.width/2, y: rect.size.width/2)
let r1 = rect.size.width/2
p.addArc(center: center, radius: abs(lineWidth - r1), startAngle: startAngle, endAngle: endAngle, clockwise: false)
p.addArc(center: center, radius: r1, startAngle: endAngle, endAngle: startAngle, clockwise: true)
p.closeSubpath()
return p
}
}
struct Wedge {
var startAngle: Double
var endAngle: Double
var color: Color
var text: String
var offset: CGSize
var rotaion: Double
var radius: CGFloat
}
struct wedge: View {
@EnvironmentObject var assesmentClass: Assesments
let wedges = [
Wedge(startAngle: -90, endAngle: -45, color: Color.yellow, text: "Assess", offset: CGSize(width: -0.0, height: -15.0), rotaion: 25, radius: 135),
Wedge(startAngle: -45, endAngle: 0, color: Color.red, text: "Paddle Out",offset: CGSize(width: 0.0, height: -20.0), rotaion: 70, radius: 130),
Wedge(startAngle: 0, endAngle: 45, color: Color.green, text: "Position",offset: CGSize(width: 0.0, height: -10.0), rotaion: 110, radius: 135),
Wedge(startAngle: 45, endAngle: 90, color: Color.blue, text: "Catch",offset: CGSize(width: 0.0, height: -10.0), rotaion: 155, radius: 135),
Wedge(startAngle: 90, endAngle: 135, color: Color.gray, text: "Take Off",offset: CGSize(width: 0.0, height: -10.0), rotaion: 205, radius: 135),
Wedge(startAngle: 135, endAngle: 180, color: Color.yellow, text: "Pop Up",offset: CGSize(width: 5.0, height: -10.0), rotaion: 245, radius: 135),
Wedge(startAngle: 180, endAngle: 225, color: Color.green, text: "Speed",offset: CGSize(width: 5.0, height: -10.0), rotaion: 290, radius: 135),
Wedge(startAngle: 225, endAngle: -90, color: Color.gray, text: "Manouvers",offset: CGSize(width: 5.0, height: -35.0), rotaion: -25, radius: 135)
]
var body: some View {
ZStack {
ForEach(0 ..< wedges.count) {
WedgeShape(
startAngle: Angle(degrees: self.wedges[$0].startAngle),
endAngle: Angle(degrees: self.wedges[$0].endAngle),
lineWidth: 44
)
.foregroundColor(self.wedges[$0].color)
//PieSlice(pies: assesmentClass.makePies())
CurvedText(text: self.wedges[$0].text, radius: self.wedges[$0].radius, spacing: 2).kerning(1).offset(self.wedges[$0].offset).foregroundColor(.black).rotationEffect(Angle(degrees: self.wedges[$0].rotaion))
}.scaledToFit()
}
}
}
这是视图的代码,正如您所看到的,我使用了硬编码值的偏移量,我相信这是问题所在,但我不确定如何获取动态值以便动态更改。
>以下是弯曲文本视图的代码。
//
// CurvedText.swift
// ombe_surf
//
// Created by Joby Ingram-Dodd on 09/04/2021.
//
import SwiftUI
private struct TextViewSizeKey: PreferenceKey {
static var defaultValue: [CGSize] { [] }
static func reduce(value: inout [CGSize], nextValue: () -> [CGSize]) {
value.append(contentsOf: nextValue())
}
}
private struct PropagateSize<V: View>: View {
var content: () -> V
var body: some View {
content()
.background(GeometryReader { proxy in
Color.clear.preference(key: TextViewSizeKey.self, value: [proxy.size])
})
}
}
private struct IdentifiableCharacter: Identifiable {
var id: String { "\(index) \(character)" }
let index: Int
let character: Character
}
extension IdentifiableCharacter {
var string: String { "\(character)" }
}
extension Array {
subscript(safe index: Int) -> Element? {
indices.contains(index) ? self[index] : nil
}
}
// MARK: - Curved Text
public struct CurvedText: View {
public var text: String
public var radius: CGFloat
internal var textModifier: (Text) -> Text = { $0 }
internal var spacing: CGFloat = 0
@State private var sizes: [CGSize] = []
private func textRadius(at index: Int) -> CGFloat {
radius - size(at: index).height / 2
}
public var body: some View {
VStack {
ZStack {
ForEach(textAsCharacters()) { item in
PropagateSize {
self.textView(char: item)
}
.frame(width: self.size(at: item.index).width,
height: self.size(at: item.index).height)
.offset(x: 0,
y: -self.textRadius(at: item.index))
.rotationEffect(self.angle(at: item.index))
}
}
.frame(width: radius * 2, height: radius * 2)
.onPreferenceChange(TextViewSizeKey.self) { sizes in
self.sizes = sizes
}
}
.accessibility(label: Text(text))
}
private func textAsCharacters() -> [IdentifiableCharacter] {
let string = String(text.reversed())
return string.enumerated().map(IdentifiableCharacter.init)
}
private func textView(char: IdentifiableCharacter) -> some View {
textModifier(Text(char.string))
.rotationEffect(.degrees(180))
}
private func size(at index: Int) -> CGSize {
sizes[safe: index] ?? CGSize(width: 1000000, height: 0)
}
private func angle(at index: Int) -> Angle {
let arcSpacing = Double(spacing / radius)
let letterWidths = sizes.map { $0.width }
let prevWidth =
index < letterWidths.count ?
letterWidths.dropLast(letterWidths.count - index).reduce(0, +) :
0
let prevArcWidth = Double(prevWidth / radius)
let totalArcWidth = Double(letterWidths.reduce(0, +) / radius)
let prevArcSpacingWidth = arcSpacing * Double(index)
let arcSpacingOffset = -arcSpacing * Double(letterWidths.count - 1) / 2
let charWidth = letterWidths[safe: index] ?? 0
let charOffset = Double(charWidth / 2 / radius)
let arcCharCenteringOffset = -totalArcWidth / 2
let charArcOffset = prevArcWidth + charOffset + arcCharCenteringOffset + arcSpacingOffset + prevArcSpacingWidth
return Angle(radians: charArcOffset)
}
}
extension CurvedText {
public func kerning(_ kerning: CGFloat) -> CurvedText {
var copy = self
copy.spacing = kerning
return copy
}
public func italic() -> CurvedText {
var copy = self
copy.textModifier = {
self.textModifier($0)
.italic()
}
return copy
}
public func bold() -> CurvedText {
fontWeight(.bold)
}
public func fontWeight(_ weight: Font.Weight?) -> CurvedText {
var copy = self
copy.textModifier = {
self.textModifier($0)
.fontWeight(weight)
}
return copy
}
}
struct CurvedText_Previews: PreviewProvider {
static var previews: some View {
Group {
CurvedText(text: "Hello World!", radius: 200)
CurvedText(text: "Hello World!", radius: 100)
.kerning(5)
.italic()
.fontWeight(.heavy)
}
.previewLayout(.sizeThatFits)
}
}
这是屏幕截图。