Skip to content

Instantly share code, notes, and snippets.

@lanserxt
Created November 10, 2025 13:24
Show Gist options
  • Select an option

  • Save lanserxt/735c5c3d02c95a20d9fb26e9afaa1194 to your computer and use it in GitHub Desktop.

Select an option

Save lanserxt/735c5c3d02c95a20d9fb26e9afaa1194 to your computer and use it in GitHub Desktop.
SwiftUI: Discardable Slider View
import SwiftUI
struct DiscardableSliderView: View {
@State private var value = 5.0
@State private var filterValue: Double = 5.0
var body: some View {
VStack {
Text("Values to filter")
DiscardableSlider(value: $filterValue, bounds: 0...10, step: 1)
Text("Initial value: \(Text(value, format: .number.rounded(rule: .up)).bold())")
}
.onChange(of: filterValue) {
print(filterValue)
}
.padding(32)
}
}
@lanserxt
Copy link
Author

And Liquid Glass version

struct DiscardableSlider<V: Strideable>: View where V : BinaryFloatingPoint, V.Stride : BinaryFloatingPoint {
    internal init(value: Binding<V>, bounds: ClosedRange<V>, step: V.Stride) {
        self._value = value
        self.bounds = bounds
        self.step = step
        self._pendingValue = State(initialValue: value.wrappedValue)
    }
    
    @Binding var value: V
    let bounds: ClosedRange<V>
    let step: V.Stride
    
    @State private var pendingValue: V
    
    @State private var showDiscard: Bool = false
    
    var body: some View {
        VStack(spacing: 4.0) {
            
            Slider(value: $pendingValue, in: bounds, step:  step) {}
                .onChange(of: pendingValue) {
                    withAnimation {
                        showDiscard = abs(pendingValue - value) > 0.1
                    }
                }
            if showDiscard {
                HStack {
                    Spacer()
                    
                    buttonsStack
                    .padding(4)
                }
                .animation(.linear,value: showDiscard)
                .transition(.move(edge: !showDiscard ? .bottom : .top).combined(with: .opacity))
            }
        }
    }
    
    private var buttonsStack: some View {
        GlassEffectContainer {
            HStack(spacing: 12.0) {
                Button {
                    withAnimation {
                        pendingValue = value
                    }
                } label: {
                    Label("Cancel", systemImage: "xmark.circle")
                        .labelStyle(.iconOnly) // compact; keep just the icon if you prefer
                        .foregroundStyle(.red)
                }
                .frame(width: 40, height: 40)
                .buttonStyle(.glass)
                
                Button {
                    value = pendingValue
                } label: {
                    Label("Save", systemImage: "checkmark.circle.fill")
                        .labelStyle(.iconOnly)
                        .font(.title3)
                        .foregroundStyle(.green)   // green checkmark
                }
                .frame(width: 40, height: 40)
                .buttonStyle(.glass)
            }
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment