Skip to content

Instantly share code, notes, and snippets.

@muukii
Created February 13, 2024 05:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save muukii/fb5b2ff037a85164d1703f96f5d8f3b9 to your computer and use it in GitHub Desktop.
Save muukii/fb5b2ff037a85164d1703f96f5d8f3b9 to your computer and use it in GitHub Desktop.
Slider.swift
import SwiftUI
@available(iOS 15, *)
struct Slider: View {
enum SliderPreferenceKey: PreferenceKey {
static var defaultValue: CGRect = .zero
static func reduce(value: inout CGRect, nextValue: () -> CGRect) {
// nextValue()
}
typealias Value = CGRect
}
@Binding var value: Int
let amplitude: Int = 45
@State private var hasAppeared = false
init(value: Binding<Int>) {
self._value = value
}
var body: some View {
VStack {
Circle()
.frame(width: 2, height: 2)
GeometryReader(content: { geometry in
ScrollViewReader { proxy in
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 4) {
ForEach(0..<25) { index in
RoundedRectangle(cornerRadius: 2)
.fill(Color(white: 0.5, opacity: 1))
.frame(width: 2, height: 20)
}
RoundedRectangle(cornerRadius: 2)
.frame(width: 2, height: 20)
ForEach(0..<25) { index in
RoundedRectangle(cornerRadius: 2)
.fill(Color(white: 0.5, opacity: 1))
.frame(width: 2, height: 20)
}
}
.background(
HStack(spacing: 0) {
ForEach(0..<100) { i in
Color.clear
.id(i - 100)
}
Color.clear
.id(0)
ForEach(1..<101) { i in
Color.clear
.id(i)
}
}
)
.background(
GeometryReader { geometry in
Color.clear.preference(
key: SliderPreferenceKey.self,
value: geometry.frame(in: .named("ScrollView"))
)
}
)
.padding(.horizontal, geometry.size.width / 2)
.onPreferenceChange(
SliderPreferenceKey.self,
perform: { rect in
guard hasAppeared else { return }
let half = (geometry.size.width - rect.size.width) / 2
let length = (geometry.size.width / 2) - half
let point = rect.origin
let offsetX = point.x
let v = half - offsetX
let normalized = v / length
let bouncingValue = normalized * CGFloat(amplitude)
let clampedValue = max(min(bouncingValue, CGFloat(amplitude)), -CGFloat(amplitude))
print(v, length, clampedValue)
self.value = Int(clampedValue)
}
)
}
.coordinateSpace(name: "ScrollView")
.onAppear(perform: {
let normalized = Double(value) / Double(amplitude)
let id = Int(normalized * 100)
print("scrollto", id, normalized, value)
proxy.scrollTo(id, anchor: .center)
hasAppeared = true
})
}
})
}
}
}
#if DEBUG
@available(iOS 15, *)
private struct SliderDemo: View {
@State var value: Int = 32
var body: some View {
VStack {
Slider(value: $value)
Text("\(value)")
HStack {
Button("32") {
value = 32
}
}
}
}
}
@available(iOS 15, *)
#Preview("Slider"){
SliderDemo()
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment