英文:
How to draw a vertical linear Gauge in SwiftUI nicely?
问题
我是新手学习SwiftUI,并最近开始着手我的第一个项目(关于可视化一些数据)。我喜欢SwiftUI中的Gauge
结构看起来,所以我想基于它设计视图。
现在,我想展示一个垂直线性仪表,但我遇到了一些问题。以下是我的代码的结果:
垂直线性仪表的底部填充看起来非常奇怪。这是我的代码:
import SwiftUI
struct SingleValueVertical: View {
@State var val: Float = 32.0
@State var MinMax: (min: Float, max: Float) = (0, 50)
var body: some View {
ZStack {
HStack (alignment: .top){
VStack(alignment: .leading) {
Image(systemName: "airplane.departure")
.foregroundColor(.white)
Text("Speed")
.font(.title2)
.foregroundColor(.white)
.opacity(0.9)
Text("\(Int(val))")
.font(.largeTitle)
.foregroundColor(.white)
}
RotatedGauge()
}
.padding([.bottom, .top], 30)
.padding([.horizontal], 20)
}
.frame(width: 200, height: 200)
.background(Color.black.opacity(0.8))
.cornerRadius(30)
}
}
struct SingleValueVertical_Previews: PreviewProvider {
static var previews: some View {
SingleValueVertical()
}
}
其中RotatedGauge
类是:
struct RotatedGauge: View {
@State var val: Float = 32.0
@State var MinMax: (min: Float, max: Float) = (0, 50)
var body: some View {
VStack {
Gauge(value: val, in: MinMax.min...MinMax.max) {
} currentValueLabel: {
} minimumValueLabel: {
Text("\(Int(MinMax.min))")
.foregroundColor(Color.green)
.rotationEffect(.degrees(90))
} maximumValueLabel: {
Text("\(Int(MinMax.max))")
.foregroundColor(Color.red)
.rotationEffect(.degrees(90))
}
.tint(Gradient(colors: [.green, .red]))
.gaugeStyle(.accessoryLinear)
.rotationEffect(.degrees(-90))
}
}
}
请原谅我的糟糕编码,但我真的想知道我的代码有什么问题。是否有更好的方法来做这个?我已经尝试了很多搜索,但没有一个结果符合我的期望。
英文:
I am new to SwiftUI and just start to struggle with my first project recently (it is about visualizing some data). I love how the Gauge
struct in SwiftUI looks, so I want to design views based on it.
Now, I want to show a vertical linear gauge, but I ran into some problems. Here is the result of my code:
It looks pretty strange that the vertical linear gauge's padding to the bottom is huge. Here is my code:
import SwiftUI
struct SingleValueVertical: View {
@State var val: Float = 32.0
@State var MinMax: (min: Float, max: Float) = (0, 50)
var body: some View {
ZStack {
HStack (alignment: .top){
VStack(alignment: .leading) {
Image(systemName: "airplane.departure")
.foregroundColor(.white)
Text("Speed")
.font(.title2)
.foregroundColor(.white)
.opacity(0.9)
Text("\(Int(val))")
.font(.largeTitle)
.foregroundColor(.white)
}
RotatedGauge()
}
.padding([.bottom, .top], 30)
.padding([.horizontal], 20)
}
.frame(width: 200, height: 200)
.background(.black.opacity(0.8))
.cornerRadius(30)
// .shadow(radius: 5)
}
}
struct SingleValueVertical_Previews: PreviewProvider {
static var previews: some View {
SingleValueVertical()
}
}
in which RotatedGauge
class is
struct RotatedGauge: View {
@State var val: Float = 32.0
@State var MinMax: (min: Float, max: Float) = (0, 50)
var body: some View {
VStack {
Gauge(value: val, in: MinMax.min...MinMax.max) {
// Image(systemName: "heart.fill")
// .foregroundColor(.red)
} currentValueLabel: {
// Text("\(Int(val))")
// .foregroundColor(Color.green)
} minimumValueLabel: {
Text("\(Int(MinMax.min))")
.foregroundColor(Color.green)
.rotationEffect(.degrees(90))
} maximumValueLabel: {
Text("\(Int(MinMax.max))")
.foregroundColor(Color.red)
.rotationEffect(.degrees(90))
}
.tint(Gradient(colors: [.green, .red]))
.gaugeStyle(.accessoryLinear)
.rotationEffect(.degrees(-90))
}
}
}
Excuse my bad coding, but I really want to know that what is wrong with my code. Is there some methods to do it more nicely?
I have tried so many googling, but none of the results gave me what I expected.
答案1
得分: 1
你可以很容易地实现自己的 GaugeStyle
,而不是将现有的样式弯曲以满足你的需求。这是线性附件计量样式的简单垂直版本:
struct VerticalAccessoryGaugeStyle: GaugeStyle {
func makeBody(configuration: Configuration) -> some View {
VStack(spacing: 0) {
configuration.maximumValueLabel
GeometryReader { proxy in
Capsule()
.fill(.tint)
.rotationEffect(.degrees(180))
Circle()
.stroke(.background, style: StrokeStyle(lineWidth: 3))
.position(x: 5, y: proxy.size.height * (1 - configuration.value))
}
.frame(width: 10)
.clipped()
configuration.minimumValueLabel
}
}
}
当像这样使用时:
Gauge(value: value, in: 0...100) {
} currentValueLabel: {
} minimumValueLabel: {
Text("0")
} maximumValueLabel: {
Text("100")
}
.gaugeStyle(VerticalAccessoryGaugeStyle())
.frame(height: 100)
.tint(Gradient(colors: [.green, .red]))
看起来像这样:
英文:
You can implement your own GaugeStyle
quite easily, instead of bending the existing ones to your needs. Here is a simple vertical version of the linear accessory gauge style:
struct VerticalAccessoryGaugeStyle: GaugeStyle {
func makeBody(configuration: Configuration) -> some View {
VStack(spacing: 0) {
configuration.maximumValueLabel
GeometryReader { proxy in
Capsule()
.fill(.tint)
.rotationEffect(.degrees(180))
Circle()
.stroke(.background, style: StrokeStyle(lineWidth: 3))
.position(x: 5, y: proxy.size.height * (1 - configuration.value))
}
.frame(width: 10)
.clipped()
configuration.minimumValueLabel
}
}
}
Which, when used like this:
Gauge(value: value, in: 0...100) {
} currentValueLabel: {
} minimumValueLabel: {
Text("0")
} maximumValueLabel: {
Text("100")
}
.gaugeStyle(VerticalAccessoryGaugeStyle())
.frame(height: 100)
.tint(Gradient(colors: [.green, .red]))
Looks like this:
答案2
得分: 0
当您旋转仪表时,您需要在旋转之前水平调整其大小,然后在旋转后垂直调整大小:
struct RotatedGauge: View {
@State var val: Float = 32.0
@State var MinMax: (min: Float, max: Float) = (0, 50)
var body: some View {
VStack {
Gauge(value: val, in: MinMax.min...MinMax.max) {
// Image(systemName: "heart.fill")
// .foregroundColor(.red)
} currentValueLabel: {
// Text("\(Int(val))")
// .foregroundColor(Color.green)
} minimumValueLabel: {
Text("\(Int(MinMax.min))")
.foregroundColor(Color.green)
.rotationEffect(.degrees(90))
} maximumValueLabel: {
Text("\(Int(MinMax.max))")
.foregroundColor(Color.red)
.rotationEffect(.degrees(90))
}
.frame(width: 160, height: 80) // 水平大小
.rotationEffect(.degrees(-90))
.frame(width: 80, height: 160) // 旋转后调整大小
.tint(Gradient(colors: [.green, .red]))
.gaugeStyle(.accessoryLinear)
// .border(Color.white)
}
}
}
也许还有其他方法,但这可以解决问题。
英文:
As you rotate the gauge you need to resize it horizontally before rotation, then vertically after rotation :
struct RotatedGauge: View {
@State var val: Float = 32.0
@State var MinMax: (min: Float, max: Float) = (0, 50)
var body: some View {
VStack {
Gauge(value: val, in: MinMax.min...MinMax.max) {
// Image(systemName: "heart.fill")
// .foregroundColor(.red)
} currentValueLabel: {
// Text("\(Int(val))")
// .foregroundColor(Color.green)
} minimumValueLabel: {
Text("\(Int(MinMax.min))")
.foregroundColor(Color.green)
.rotationEffect(.degrees(90))
} maximumValueLabel: {
Text("\(Int(MinMax.max))")
.foregroundColor(Color.red)
.rotationEffect(.degrees(90))
}
.frame(width: 160, height: 80) // horizontal size
.rotationEffect(.degrees(-90))
.frame(width: 80, height: 160) // resize after rotation
.tint(Gradient(colors: [.green, .red]))
.gaugeStyle(.accessoryLinear)
// .border(Color.white)
}
}
}
There may be another way, but this can do the trick.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论