问题描述
我正在创建一个折线图视图,灵感来自 this blog post。
线条是用 Path 绘制的,渐变是用 LinearGradient 和蒙版绘制的,它们相互叠加。
我的主要问题是,正如您在屏幕截图中看到的,所有渐变的开始都有一个斜率,如果该值为零,它们似乎过早关闭(末端似乎也过早削减,但这不是我的主要问题)。如果值 > 0(如橙色),则开始似乎也为时已晚。
我想要的是让渐变完全填充红色箭头所指的部分(去除斜坡和突然切割)。
但是我无法通过调整幻数来找到解决方案。此外,我更愿意了解正在发生的事情,而不是四处闲逛。
我做错了什么?
我制作了一个可重现的示例,粘贴这是一个 ContentView:
struct ContentView: View {
@State var values: [Double] = [0,1,2,6,4,0]
@State var totalMaxnum: Double = 6
var body: some View {
GeometryReader { proxy in
ScrollView {
vstack {
// some other view
vstack {
vstack {
RoundedRectangle(cornerRadius: 5)
.overlay(
ZStack {
Color.white.opacity(0.95)
drawValuesLine(values: values,color: .blue)
}
)
.overlay(
ZStack {
Color.clear
drawValuesGradient(values: values,start: .orange,end: .red)
}
)
.frame(width: proxy.size.width - 40,height: proxy.size.height / 4)
// some other view
}
// some other view
}
}
}
}
}
func drawValuesLine(values: [Double],color: Color) -> some View {
GeometryReader { geo in
Path { p in
let scale = (geo.size.height - 40) / CGFloat(totalMaxnum)
var index: CGFloat = 0
let y1: CGFloat = geo.size.height - 10 - (CGFloat(values[0]) * scale)
let y = y1.isNaN ? 0 : y1
p.move(to: CGPoint(x: 8,y: y))
for _ in values {
if index != 0 {
let x1: CGFloat = 8 + ((geo.size.width - 16) / CGFloat(values.count)) * index
let x = x1.isNaN ? 0 : x1
let yy: CGFloat = geo.size.height - 10 - (CGFloat(values[Int(index)]) * scale)
let y = yy.isNaN ? 0 : yy
p.addLine(to: CGPoint(x: x,y: y))
}
index += 1
}
}
.stroke(style: strokeStyle(linewidth: 3,lineCap: .round,lineJoin: .round,miterLimit: 80,dash: [],dashPhase: 0))
.foregroundColor(color)
}
}
func drawValuesGradient(values: [Double],start: Color,end: Color) -> some View {
LinearGradient(gradient: Gradient(colors: [start,end]),startPoint: .top,endPoint: .bottom)
.padding(.bottom,1)
.opacity(0.8)
.mask(
GeometryReader { geo in
Path { p in
let scale = (geo.size.height - 40) / CGFloat(totalMaxnum)
var index: CGFloat = 0
// Move to the starting point
let y1: CGFloat = geo.size.height - (CGFloat(values[Int(index)]) * scale)
let y = y1.isNaN ? 0 : y1
p.move(to: CGPoint(x: 8,y: y))
// Draw the lines
for _ in values {
if index != 0 {
let x1: CGFloat = 8 + ((geo.size.width - 16) / CGFloat(values.count)) * index
let x = x1.isNaN ? 0 : x1
let yy: CGFloat = geo.size.height - 10 - (CGFloat(values[Int(index)]) * scale)
let y = yy.isNaN ? 0 : yy
p.addLine(to: CGPoint(x: x,y: y))
}
index += 1
}
// Close the subpath
let x1: CGFloat = 8 + ((geo.size.width - 16) / CGFloat(values.count)) * (index - 1)
let x = x1.isNaN ? 0 : x1
p.addLine(to: CGPoint(x: x,y: geo.size.height))
p.addLine(to: CGPoint(x: 8,y: geo.size.height))
p.closeSubpath()
}
}
)
}
}
您可以在屏幕截图中看到橙色渐变如何无法正确填充线条下方的所有区域: