You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 02:35:19