【SwiftUI】swift自定义一个指针仪表盘,自定义Path绘制。


看看效果:

IMG_1242

最开始的时候使用Path绘制的弧形曲线填充渐变,后来圆角拐点的时候老是有问题,就换了一个实现方式,使用曲线绘制给曲线末端设置圆角就ok了。

1.思路:使用ZStack一层层叠加后,设置同心圆,添加一个指针图片与当前角度绑定一起,这个角度也影响弧形进度的角度。叠加两个进度,一个是默认的灰色,角度180,另一个是当前进度随之下面的slider的改变而改变,画进度条后,不用Fill,先绘制一条弧线,然后给线添加一个边(Stroke),这个边的大小就是进度的厚度,边的颜色就是进度条的颜色。

代码:有注释

//
//  ContentView.swift
//  swiftUiDemo  指针仪表盘
//  http://blog.borebooks.top
//  Created by IWH718 on 2020/10/20.
//

import SwiftUI

struct ContentView: View {
  
    let leftG1 = 1...10
  
    @State var index:CGFloat = 0
  
    let colors = Gradient(colors: [Color.yellow,Color.red,Color.orange ])
  
  
  
    var body: some View {
  
        VStack{
            Text("SwiftUI 🌰").font(.title).bold().padding()
  
            //仪表盘容器
            ZStack{
                //同心圆
                Group{
                    Circle().stroke(Color.gray).frame(width:220,height:220)
                    Circle().fill(Color.white).frame(width:180,height:180)
                    Circle().fill(Color.blue).frame(width:80,height:80)
                    Circle().fill(Color.white).frame(width:60,height: 60)
                    Circle().fill(Color.blue).frame(width:40,height: 40)
                }
                Group{
                    //左侧仪表点
                    ForEach(leftG1,id:\.self){i  in
                        Text("·") .frame(width:10,height:10)
                            .offset( x: 0,  y: -70) .rotationEffect(.init(degrees:  Double(i * 9 ) * -1 ))
                            .foregroundColor( (Double(i * 9 ) * -1) ==  Double(index * 9) ? Color.blue :Color.gray )
                    }
                }
                Group{
                    //右侧仪表点
                    ForEach(leftG1,id:\.self){i  in
                        Text("·").frame(width:10,height:10)
                            .offset( x: 0, y: -70) .rotationEffect(.init(degrees:  Double(i * 9) ))
                            .foregroundColor( (Double(i * 9 ) ) ==  Double(index * 9) ? Color.blue :Color.gray )
                    }
                }
  
                //仪表数据
                VStack{
                    Text("\(Int(index))")
                    Text("value")
                }.offset(x: 0, y: 80).foregroundColor(Color.gray).font(.system(size: 13))
  
                GeometryReader{
                    proxy in
                    //进度条背景
                    Path{ path in
                        path.move(to: CGPoint(x:proxy.size.width / 2 - 90 , y:proxy.size.height / 2))
                        //绘制上弧形
                        path.addArc(center: CGPoint(x:proxy.size.width / 2   ,y:proxy.size.height / 2 ), radius: CGFloat(90), startAngle: Angle.init(degrees: -180), endAngle: Angle.init(
                                        degrees: Double(0) ), clockwise: false)
          
                    }
                    .stroke(Color.gray,style: StrokeStyle(lineWidth: 15, lineCap: .round))
      
                    //进度条
                    Path{ path in
                        path.move(to: CGPoint(x:proxy.size.width / 2 - 90 , y:proxy.size.height / 2))
                        //绘制上弧形
                        path.addArc(center: CGPoint(x:proxy.size.width / 2  ,y:proxy.size.height / 2 ), radius: CGFloat(90), startAngle: Angle.init(degrees: -180), endAngle: Angle.init(
                                        degrees: Double((-1 * (180 - index * 9))) ), clockwise: false)
          
                    }
                    .stroke(LinearGradient(gradient: colors,startPoint: .topLeading,endPoint: .bottomTrailing),style: StrokeStyle(lineWidth: 15, lineCap: .round))
      
                }.frame(width:220,height:220)
                //指针
                Image("arrow").resizable().frame(width:60,height:60).offset(x: 0, y: -16)
                    .rotationEffect(.init(degrees:  Double(index * 9) - 90 )).animation(.linear)
  
            }.padding()
  
            Slider(value: $index, in: 0...19, step:1){_ in
                withAnimation{
                    index += 1
                }
            }.padding()
  
        }
  
  
  
  
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

文章作者: 2winter
文章链接: https://2winter.com
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 2winter !