Custom slider thumb not showing initially, only after toggle

struct ContentView: View {
  @State private var sliderValue = 50.0
  @State private var showSlider = true

    var body: some View {
      VStack {
        if showSlider {
          BullSlider(value: $sliderValue, in: 1.0...100.0)
        }
        Button("Toggle") {showSlider.toggle()}.padding()
      }
    }
}

struct BullSlider: View {
  @Binding var value: Double
  var bounds: ClosedRange<Double>

  init(value: Binding<Double>, in bounds: ClosedRange<Double>) {
    let thumbImage = BullThumb().snapshot()
    UISlider.appearance().setThumbImage(thumbImage, for: .normal)
    self.bounds = bounds
    self._value = value
  }

  var body: some View {
    Slider(value: $value, in: bounds)
  }
}


struct BullThumb: View {
  var body: some View {
    VStack {
      ZStack {
        Circle()
          .frame(width: 50, height: 50)
          .foregroundColor(.white)
        Circle()
          .strokeBorder(lineWidth: 6)
          .frame(width: 44, height: 44)
        Circle()
          .strokeBorder(lineWidth: 6)
          .frame(width: 24, height: 24)
      }
      .foregroundColor(.blue)

      Spacer()
        .frame(height: 60)
    }
  }
}


extension View {
  func snapshot() -> UIImage {
    let controller = UIHostingController(rootView: self)
    let view = controller.view
    let targetSize = CGSize(width: 50, height: 60)//controller.view.intrinsicContentSize

    view?.bounds = CGRect(origin: CGPoint(x: 0, y: 0), size: targetSize)
    view?.backgroundColor = .clear

    let renderer = UIGraphicsImageRenderer(size: targetSize)
    return renderer.image { _ in
      view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
    }
  }
}

Accepted Reply

struct ContentView: View {
    @State private var sliderValue = 50.0
    @State private var showSlider = true

    var body: some View {
        VStack {
            BullSlider(value: $sliderValue, in: 1.0...100.0)
                .opacity(showSlider ? 1 : 0)
            Button("Toggle") {
                withAnimation {
                    showSlider.toggle()
                }
            }
            .padding()
        }
    }
}

struct BullSlider: View {
    @Binding var value: Double
    var bounds: ClosedRange<Double>

    init(value: Binding<Double>, in bounds: ClosedRange<Double>) {
        self.bounds = bounds
        self._value = value
    }

    var body: some View {
        Slider(value: $value, in: bounds)
            .onAppear{
                let thumbImage = ImageRenderer(content: bullThumb).uiImage ?? UIImage()
                UISlider.appearance().setThumbImage(thumbImage, for: .normal)
            }
    }

    var bullThumb: some View {
        VStack {
            ZStack {
                Circle()
                  .frame(width: 50, height: 50)
                  .foregroundColor(.white)
                Circle()
                  .strokeBorder(lineWidth: 6)
                  .frame(width: 44, height: 44)
                Circle()
                  .strokeBorder(lineWidth: 6)
                  .frame(width: 24, height: 24)
            }
            .foregroundColor(.blue)
        }
        .frame(width: 50, height: 60)
    }
}
  • Cheers mate! All works perfectly now.

Add a Comment

Replies

struct ContentView: View {
    @State private var sliderValue = 50.0
    @State private var showSlider = true

    var body: some View {
        VStack {
            BullSlider(value: $sliderValue, in: 1.0...100.0)
                .opacity(showSlider ? 1 : 0)
            Button("Toggle") {
                withAnimation {
                    showSlider.toggle()
                }
            }
            .padding()
        }
    }
}

struct BullSlider: View {
    @Binding var value: Double
    var bounds: ClosedRange<Double>

    init(value: Binding<Double>, in bounds: ClosedRange<Double>) {
        self.bounds = bounds
        self._value = value
    }

    var body: some View {
        Slider(value: $value, in: bounds)
            .onAppear{
                let thumbImage = ImageRenderer(content: bullThumb).uiImage ?? UIImage()
                UISlider.appearance().setThumbImage(thumbImage, for: .normal)
            }
    }

    var bullThumb: some View {
        VStack {
            ZStack {
                Circle()
                  .frame(width: 50, height: 50)
                  .foregroundColor(.white)
                Circle()
                  .strokeBorder(lineWidth: 6)
                  .frame(width: 44, height: 44)
                Circle()
                  .strokeBorder(lineWidth: 6)
                  .frame(width: 24, height: 24)
            }
            .foregroundColor(.blue)
        }
        .frame(width: 50, height: 60)
    }
}
  • Cheers mate! All works perfectly now.

Add a Comment