How to trigger a function when a Slider changes in SwiftUI?

Viewed 6288

I'm trying to trigger the sliderchanged() function when the slider value changes, I might be missing something very basic but every similar thing I've found isn't working. Isn't there anything like "action" for the Slider or the old "ValueChanged" action?

Here's my code:

struct CustomSlider1: View {

    @State var progress: Float = 0.5
    var body: some View {

       VStack{
        Slider(value: $progress)
            .padding(.all)
            Text(String(progress))          
        }        
    }

    func sliderchanged() {
        //do things 
    }
}

Thanks!!

4 Answers

You can make a custom Binding that calls the function in the Binding's setter:

@State var progress: Float = 0.5
var body: some View {

   VStack{
       Slider(value: Binding(get: {
           self.progress
       }, set: { (newVal) in
           self.progress = newVal
           self.sliderChanged()
       }))
       .padding(.all)
       Text(String(progress))
    }
}

func sliderChanged() {
    print("Slider value changed to \(progress)")
}

Swift 5, iOS 13

Another option, simple using a State variables and a closure.

@State var alpha = 65
@State var alphaToShow = ""

Slider(value: $alpha, in: 65...90,step: 1,onEditingChanged: { data in
  self.alphaToShow = String(Character(UnicodeScalar(Int(self.alpha))!))
  // execute more code here
}
}).padding()
Text(alphaToShow)

Yet another approach to get continuous updates using onChange modifier.

import SwiftUI

struct SliderOnChange: View {
    @State var progress: Float = 0.5

    var body: some View {
        VStack{
            Slider(value: self.$progress)
                .onChange(of: self.progress) { newProgress in
                    self.sliderChanged(to: newProgress)
                }
            Text(String(self.progress))
        }
    }

    func sliderChanged(to progress: Float) {
        print("Slider value changed to \(progress)")
    }
}

More Combine way:

import Combine

class ViewModel: ObservableObject {

    @Published var sliderValue: Double = 0
    private var subscriptions = [AnyCancellable]()
    
    init() {
        $sliderValue.sink(receiveValue: {
            print("sliderValue: ", $0)
        }).store(in: &subscriptions)
    }
}
Related