如何在SwiftUI中使用图片创建自定义垂直车辆车速仪表盘
自定义SwiftUI车速表实现方案
你的现有代码已经搭建了基础的刻度布局,但缺少根据车速动态激活对应刻度的核心逻辑,同时需要优化布局和状态切换的流畅性。以下是完善后的实现代码:
完整ContentView代码
import SwiftUI struct SpeedometerGaugeStyle: GaugeStyle { // 总刻度数,对应0-160车速区间,每8单位一个刻度 private let totalTicks = 20 private let maxSpeed: Double = 160 func makeBody(configuration: Configuration) -> some View { let progress = configuration.value / maxSpeed // 计算当前需要高亮的刻度数量 let activeTicks = Int(progress * Double(totalTicks)) VStack(spacing: 4) { ForEach(1...totalTicks, id: \.self) { index in // 刻度长度随索引递增逐步缩短(从长到短排列) let tickWidth = Double(100 - (index * 2)) RoundedRectangle(cornerSize: CGSize(width: 10, height: 10)) .frame(width: tickWidth, height: 10) // 激活刻度用对应渐变,未激活刻度显示灰色 .foregroundStyle(index <= activeTicks ? ColorGradient.getGradient(for: index) : .gray.opacity(0.3)) .animation(.easeInOut(duration: 0.2), value: activeTicks) } } .frame(width: 200) // 在顶部叠加显示当前车速数值 .overlay(alignment: .top) { configuration.currentValueLabel .font(.largeTitle) .fontWeight(.bold) .padding(.bottom, 20) } } struct ColorGradient { static func getGradient(for index: Int) -> LinearGradient { switch index { case 1...4: return LinearGradient(colors: [ .red, .red.opacity(0.7), .red.opacity(0.5) ], startPoint: .bottom, endPoint: .top) case 5...8: return LinearGradient(colors: [ .orange, .orange.opacity(0.7), .orange.opacity(0.5) ], startPoint: .bottom, endPoint: .top) case 9...16: return LinearGradient(colors: [ .cyan, .cyan.opacity(0.7), .cyan.opacity(0.5) ], startPoint: .bottom, endPoint: .top) default: return LinearGradient(colors: [ .green, .green.opacity(0.8), .green.opacity(0.6) ], startPoint: .bottom, endPoint: .top) } } } } struct CustomGaugeView: View { @State private var currentSpeed = 45.0 @State private var animateGradient = false var body: some View { VStack(spacing: 30) { Gauge(value: currentSpeed, in: 0...160) { Text("车速表") .foregroundColor(.white) .font(.title) } currentValueLabel: { Text("\(Int(currentSpeed))") .foregroundColor(.white) } .gaugeStyle(SpeedometerGaugeStyle()) .frame(height: 300) .background(.black.opacity(0.8)) .cornerRadius(20) Slider(value: $currentSpeed, in: 0...160, step: 1) { Text("调整车速") } minimumValueLabel: { Text("0") } maximumValueLabel: { Text("160") } .tint(.blue) } .padding() .background(.gray.opacity(0.1)) .preferredColorScheme(.dark) } }
Main入口代码
@main struct Speedometer_DemoApp: App { var body: some Scene { WindowGroup { CustomGaugeView() .previewDisplayName("CustomGaugeView") } } }
关键优化说明
- 动态刻度激活:通过
configuration.value计算车速进度,自动确定需要高亮的刻度数量,未激活刻度统一显示灰色 - 平滑动画过渡:给刻度颜色切换添加动画,让车速变化时视觉过渡更自然
- 视觉布局优化:将车速数值固定在仪表盘顶部,添加深色背景增强科技感,完善Slider的刻度显示
- 颜色区间修正:修复了原代码中区间重复匹配的问题,确保每个刻度对应唯一的颜色渐变
内容的提问来源于stack exchange,提问作者Keval Gajjar
相关产品推荐
相关产品推荐

