SwiftUI lockscreen widget Gauge accessoryCircular modifier how to set value to empty like weather 0% Precipitation probability

609 views Asked by At

I tried set value to 0, -1, and 999999, and didn't work. My code:

Gauge(
   value: -1,
   label: { Text("label") },
   currentValueLabel: { Text("4") },
   minimumValueLabel: { Text("9") },
   maximumValueLabel: { Text("30") }
)
.gaugeStyle(.accessoryCircular)

Result: enter image description here

And I want to: enter image description here

2

There are 2 answers

0
fish On
struct CustomGaugeStyle: GaugeStyle {
    let lineWidth: Double = 5.5
    func makeBody(configuration: Configuration) -> some View {
        GeometryReader { geometry in
            ZStack {
                Circle()
                    .trim(from: 0, to: 0.75)
                    .stroke(Color(.lightGray).opacity(0.5), style: StrokeStyle(lineWidth: lineWidth, lineCap: .round, lineJoin: .round))
                    .rotationEffect(.degrees(135))
                
                Circle()
                    .trim(from: -0.3, to: 0.75 * configuration.value)
                    .stroke(Color.orange.gradient, style: StrokeStyle(lineWidth: lineWidth, lineCap: .round, lineJoin: .round))
                    .rotationEffect(.degrees(135))
                configuration.currentValueLabel
                configuration.label
                    .offset(y: 20)
            }
        }
        .aspectRatio(contentMode: .fit)
    }
}

struct CustomCircleView: View {
    @State private var innerRingFill = 50.0
    var body: some View {
        ZStack {
            Gauge(value: innerRingFill, in: 0...100) {
                Image(systemName: "gauge.medium")                    .resizable()
                    .scaledToFit()
                    .frame(width: 20, height: 15)
            } currentValueLabel: {
                Text("\(innerRingFill.formatted(.number))")
                    .font(.system(size: 17))
            }
            .frame(width: 53, height: 53)
            .gaugeStyle(CustomCircleView())
        }
    }
}

Result of code running

1
JanApotheker On

Here's a more flexible solution that does not use GeometryReader and has the correct insets so the circles are not cut off on the sides. Plus, it uses the tint color.

enter image description here

struct CustomProgressGaugeStyle: GaugeStyle {
    let lineWidth: CGFloat = 6
    
    func makeBody(configuration: Configuration) -> some View {
            ZStack {
                Circle()
                    .trim(from: 0, to: 0.75)
                    .stroke(
                        .tint.opacity(0.4),
                        style: .init(lineWidth: lineWidth, lineCap: .round, lineJoin: .round)
                    )
                    .rotationEffect(.degrees(135))

                Circle()
                    .trim(from: -0.3, to: 0.75 * configuration.value)
                    .stroke(
                        .tint,
                        style: .init(lineWidth: lineWidth, lineCap: .round, lineJoin: .round)
                    )
                    .rotationEffect(.degrees(135))
                
                configuration.currentValueLabel
                    .padding(.horizontal, lineWidth)
            }
            .padding(lineWidth/2)
            .overlay(alignment: .bottom) {
                configuration.label
                    .padding(.horizontal, lineWidth * 2)
            }
    }
}

Usage:

var body: some View {
        Gauge(
            value: 0.25,
            label: {
                Label(
                    title: { Text("Umbrella") },
                    icon: { Image(systemName: "umbrella.fill") }
                )
                .labelStyle(.iconOnly)
                .bold()
                .foregroundStyle(tintColor)
                .font(.caption)
            },
            currentValueLabel: {
                Text("50%")
                    .font(.title)
                    .lineLimit(1)
                    .minimumScaleFactor(0.33)
            }
        )
        .gaugeStyle(CustomProgressGaugeStyle())
        .labelStyle(.iconOnly)
        .tint(.blue)
    }