我正在尝试制作一张如图所示的图表。
下面的代码很好,但是我真的很希望每个楔形的边框都带有一个内部笔触(而不是居中):
import SwiftUI
struct WedgeShape: Shape {
var startAngle: Angle
var endAngle: Angle
func path(in rect: CGRect) -> Path {
var p = Path()
p.addArc(
center: CGPoint(x: rect.size.width/2, y: rect.size.width/2),
radius: rect.size.width/2,
startAngle: startAngle,
endAngle: endAngle,
clockwise: false
)
return p
}
}
struct Wedge {
var startAngle: Double
var endAngle: Double
var color: Color
}
struct ContentView: View {
var wedges = [
Wedge(startAngle: 0, endAngle: 90, color: Color.red),
Wedge(startAngle: 90, endAngle: 180, color: Color.green),
Wedge(startAngle: 180, endAngle: 360, color: Color.blue)
]
var body: some View {
ZStack {
ForEach(0 ..< wedges.count) {
WedgeShape(
startAngle: Angle(degrees: self.wedges[$0].startAngle),
endAngle: Angle(degrees: self.wedges[$0].endAngle)
)
.stroke(self.wedges[$0].color, lineWidth: 44)
}
}
}
}
我知道我可以简单地调整视图的框架来说明笔划。但是,我想要类似Circle().strokeBorder(Color.green, lineWidth: 44)
之类的笔画已被考虑的东西。 InsettableShape
协议看起来可能对此有所帮助,但是我不确定如何使用inset(by:)
方法。
答案 0 :(得分:1)
这是我创建楔形形状的方式。我绘制了楔形的完整路径,然后可以设置foregroundColor
。只需更改a0
和a1
即可更改楔形的长度。
struct WedgeShape: Shape {
func path(in rect: CGRect) -> Path {
var p = Path()
let a0 = Angle(degrees: 0.0)
let a1 = Angle(degrees: 270.0)
let cen = CGPoint(x: rect.size.width/2, y: rect.size.width/2)
let r0 = rect.size.width/3.5
let r1 = rect.size.width/2
p.addArc(center: cen, radius: r0, startAngle: a0, endAngle: a1, clockwise: false)
p.addArc(center: cen, radius: r1, startAngle: a1, endAngle: a0, clockwise: true)
p.closeSubpath()
return p
}
}
// Then in your `View`
var body: some View {
WedgeShape()
.frame(width: 20, height: 20, alignment: .center)
.foregroundColor(.green)
}
答案 1 :(得分:1)
借助strokedPath()
,足以像这样调整rect
:
struct Ring: Shape {
var progress: Double = 0.0
var thickness: Double = 10.0
func path(in rect: CGRect) -> Path {
let halfThickness = CGFloat(thickness / 2.0)
let rect = rect.insetBy(dx: halfThickness, dy: halfThickness)
return Path() {
$0.addArc(center: CGPoint(x: rect.midX, y: rect.midY),
radius: min(rect.width, rect.height) / 2,
startAngle: Angle(degrees: -90),
endAngle: Angle(degrees: -90 + 360 * progress),
clockwise: false)
}.strokedPath(StrokeStyle(lineWidth: CGFloat(thickness), lineCap: .round))
}
var animatableData: Double {
get { progress }
set { progress = min(1.0, max(0, newValue)) }
}
}
然后就
Ring(progress: 0.5).foregroundColor(.red)
答案 2 :(得分:0)
基于Ricky Padilla的答案的更新解决方案,该解决方案重构了WedgeShape
以在呼叫站点获取startAngle
,endAngle
和lineWidth
。
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
}
struct ContentView: View {
let wedges = [
Wedge(startAngle: -45, endAngle: 45, color: Color.blue),
Wedge(startAngle: 45, endAngle: 180, color: Color.green),
Wedge(startAngle: 180, endAngle: -45, color: Color.red)
]
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)
}
}
}
}
此外,还可以使用平均乔的答案:
import SwiftUI
struct WedgeShape: Shape {
var progress: Double
var lineWidth: CGFloat
var lineCap: CGLineCap = .butt
func path(in rect: CGRect) -> Path {
let insetWidth = lineWidth/2
let rect = rect.insetBy(dx: insetWidth, dy: insetWidth)
return Path() {
$0.addArc(
center: CGPoint(x: rect.midX, y: rect.midY),
radius: min(rect.width, rect.height)/2,
startAngle: Angle(degrees: -90),
endAngle: Angle(degrees: -90 + 360 * progress),
clockwise: false
)
}
.strokedPath(StrokeStyle(lineWidth: lineWidth, lineCap: lineCap))
}
}
struct Wedge {
var progress: Double
var color: Color
}
struct ContentView: View {
let wedges = [
Wedge(progress: 1, color: Color.green),
Wedge(progress: 0.625, color: Color.blue),
Wedge(progress: 0.375, color: Color.red)
]
var body: some View {
ZStack {
ForEach(0 ..< wedges.count) {
WedgeShape(
progress: self.wedges[$0].progress,
lineWidth: 44
)
.foregroundColor(self.wedges[$0].color)
}
}
.rotationEffect(Angle(degrees: -90))
}
}
答案 3 :(得分:0)
我无法透露姓名的人要求我将这段代码留在这里。他注意到运行安全并且不会窃取您的加密货币。基于Ricky Padilla和JWK的示例。
struct WedgeShape: Shape {
let startAngle: Angle
let endAngle: Angle
let outterScale: CGFloat
let innerScale: 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: outterScale*rect.size.width/2,
//radius: abs(lineWidth - r1),
startAngle: startAngle,
endAngle: endAngle,
clockwise: false)
p.addArc(center: center,
//radius: abs(lineWidth - r1),
radius: innerScale*rect.size.width/6,
startAngle: endAngle,
endAngle: startAngle,
clockwise: true)
p.closeSubpath()
return p
}
}
struct Wedge {
var startAngle: Double
var endAngle: Double
var color: Color
}
struct ContentViewWedge: View {
let pokemonWedges = [
//Wedge(startAngle: -45, endAngle: 45, color: Color.blue),
Wedge(startAngle: 90, endAngle: 270, color: Color.white),
Wedge(startAngle: -90, endAngle: 90, color: Color.red)
]
let backgroundWedge = Wedge(startAngle: 0, endAngle: 360, color: Color.black)
var body: some View {
ZStack(alignment: .center) {
WedgeShape(startAngle: Angle(degrees: self.backgroundWedge.startAngle-90),
endAngle: Angle(degrees: self.backgroundWedge.endAngle-90),
outterScale: 1.07,
innerScale: 1)
.foregroundColor(self.backgroundWedge.color)
WedgeShape(
startAngle: Angle(degrees: self.pokemonWedges[1].startAngle-90),
endAngle: Angle(degrees: self.pokemonWedges[1].endAngle-90),
outterScale: 1,
innerScale: 1.3
).foregroundColor(self.pokemonWedges[1].color).offset(y: -3)
WedgeShape(
startAngle: Angle(degrees: self.pokemonWedges[0].startAngle-90),
endAngle: Angle(degrees: self.pokemonWedges[0].endAngle-90),
outterScale: 1,
innerScale: 1.3
).foregroundColor(self.pokemonWedges[0].color).offset(y: +3)
}
.aspectRatio(1, contentMode: .fit)
.padding(20)
}
}
struct WedgeShapeView_Previews: PreviewProvider {
static var previews: some View {
ContentViewWedge()
}
}
答案 4 :(得分:0)
我更喜欢使用带有修整效果的圆形
struct WedgeView: View {
let lineWidth: CGFloat = 60
var body: some View {
ZStack {
Circle()
.trim(from: 0, to: 0.4)
.stroke(Color.red, style: StrokeStyle(lineWidth: lineWidth, lineCap: .butt)
).rotationEffect(.degrees(-180))
Circle()
.trim(from: 0, to: 0.2)
.stroke(Color.blue, style: StrokeStyle(lineWidth: lineWidth, lineCap: .butt)
).rotationEffect(.degrees(-180 + 360.0 * 0.4))
Circle()
.trim(from: 0, to: 0.4)
.stroke(Color.green, style: StrokeStyle(lineWidth: lineWidth, lineCap: .butt)
).rotationEffect(.degrees(-180.0 + 360.0 * 0.6)) // 0.6 = 0.4 + 0.2
}
// Stroke draws over the edge, so we add some padding to keep things within the frame
.padding(lineWidth/2)
}
}
所有内容都在此处进行了硬编码,但是您可以理解要点。