iOS 15中用SwiftUI原生实现可随滑块调整的折线图(无第三方库)
iOS 15 SwiftUI 原生折线图实现方案(支持滑块联动)
当然可以用SwiftUI原生组件实现,完全不需要依赖第三方库。下面是完整的可运行示例,包含折线绘制、动态点及标签,且支持通过滑块调整数据实时更新。
完整代码示例
import SwiftUI // 折线图数据模型 struct ChartDataPoint: Identifiable { let id = UUID() let xValue: Double var yValue: Double let label: String } // 自定义折线Shape struct LineChartShape: Shape { let dataPoints: [ChartDataPoint] let chartFrame: CGRect func path(in rect: CGRect) -> Path { var path = Path() guard !dataPoints.isEmpty else { return path } // 计算坐标转换比例(适配图表容器大小) let maxY = dataPoints.map { $0.yValue }.max() ?? 1 let minY = dataPoints.map { $0.yValue }.min() ?? 0 let yRange = maxY - minY let xStep = rect.width / CGFloat(dataPoints.count - 1) // 起始点 let firstPoint = dataPoints[0] let startX = rect.minX let startY = rect.maxY - ((firstPoint.yValue - minY) / yRange) * rect.height path.move(to: CGPoint(x: startX, y: startY)) // 绘制折线 for index in 1..<dataPoints.count { let point = dataPoints[index] let x = rect.minX + xStep * CGFloat(index) let y = rect.maxY - ((point.yValue - minY) / yRange) * rect.height path.addLine(to: CGPoint(x: x, y: y)) } return path } } struct LineChartView: View { @State private var adjustmentValue: Double = 5.0 @State private var chartData: [ChartDataPoint] = [ ChartDataPoint(xValue: 1, yValue: 3, label: "Jan"), ChartDataPoint(xValue: 2, yValue: 7, label: "Feb"), ChartDataPoint(xValue: 3, yValue: 5, label: "Mar"), ChartDataPoint(xValue: 4, yValue: 9, label: "Apr"), ChartDataPoint(xValue: 5, yValue: 6, label: "May") ] var body: some View { VStack(spacing: 20) { // 滑块控制 Slider(value: $adjustmentValue, in: 0...10, step: 0.5) .padding(.horizontal) // 折线图容器 ZStack { // 绘制折线 LineChartShape(dataPoints: chartData, chartFrame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width - 40, height: 200)) .stroke(Color.blue, lineWidth: 2) // 绘制数据点及标签 ForEach($chartData) { $point in VStack { Text("\(point.yValue, specifier: "%.1f")") .font(.caption) .foregroundColor(.red) .offset(y: -15) Circle() .fill(Color.red) .frame(width: 8, height: 8) Text(point.label) .font(.caption) .foregroundColor(.gray) .offset(y: 15) } .position( x: (UIScreen.main.bounds.width - 40) * CGFloat(point.xValue - 1) / CGFloat(chartData.count - 1) + 20, y: 200 - ((point.yValue - (chartData.map { $0.yValue }.min() ?? 0)) / (chartData.map { $0.yValue }.max() ?? 1 - (chartData.map { $0.yValue }.min() ?? 0))) * 200 ) .onChange(of: adjustmentValue) { newValue in // 模拟滑块调整数据逻辑,可根据需求自定义 point.yValue = newValue + Double.random(in: 0...3) } } } .frame(height: 250) .padding(.horizontal) } } } struct LineChartView_Previews: PreviewProvider { static var previews: some View { LineChartView() .previewDevice(PreviewDevice(rawValue: "iPhone 13")) .previewDisplayName("iOS 15") } }
关键部分解析
- 折线绘制:通过自定义
LineChartShape,利用Path将数据点转换为屏幕坐标,自动适配容器尺寸,保证折线在不同设备上的显示一致性。 - 滑块联动:使用
@State绑定滑块数值,通过onChange监听滑块变化,实时更新每个数据点的yValue,触发视图重绘。 - 动态点与标签:通过
ForEach遍历数据点,计算每个点的屏幕坐标,叠加显示圆形标记、数值标签和横轴标签,随数据变化自动调整位置。
这个方案完全基于SwiftUI原生API,兼容iOS 15及以上系统,无需引入任何第三方库,且可以根据需求自定义样式(比如折线颜色、点大小、标签字体等)。
内容的提问来源于stack exchange,提问作者tHatpart
相关产品推荐
相关产品推荐

