Skip to content

Instantly share code, notes, and snippets.

@alikaragoz
Created October 12, 2023 12:20
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save alikaragoz/f161988253776f86540371a6520e251f to your computer and use it in GitHub Desktop.
Save alikaragoz/f161988253776f86540371a6520e251f to your computer and use it in GitHub Desktop.
iOS Control Center Rubber Band Swift
import SwiftUI
struct RubberBandSwitch: View {
enum Const {
static let shapeSize: CGSize = .init(width: 90.0, height: 190.0)
static let cornerRadius: CGFloat = 26.0
}
@State var value = 0.5
@State var hScale = 1.0
@State var vScale = 1.0
@State var anchor: UnitPoint = .center
@State var yOffset: CGFloat = 0.0
@State var isTouching = false
@State var scale: CGFloat = 1.0
@State var startValue: CGFloat = 0.0
var body: some View {
ZStack {
wallpaper
slider
.clipShape(RoundedRectangle(cornerRadius: Const.cornerRadius, style: .continuous))
.frame(width: Const.shapeSize.width, height: Const.shapeSize.height)
.scaleEffect(x: hScale, y: vScale, anchor: anchor)
.offset(x: 0, y: yOffset)
.gesture(DragGesture(minimumDistance: 0)
.onChanged { drag in
if !isTouching {
startValue = value
}
isTouching = true
var value = startValue - (drag.translation.height / Const.shapeSize.height)
self.value = min(max(value, 0.0), 1.0)
var anchor: UnitPoint = .center
var yOffset: CGFloat = 0.0
if value > 1 {
value = sqrt(sqrt(sqrt(value)))
yOffset = Const.shapeSize.height * (1 - value) / 2.0
anchor = .bottom
} else if value < 0 {
value = sqrt(sqrt(sqrt(1 - value)))
yOffset = -Const.shapeSize.height * (1 - value) / 2.0
anchor = .top
} else {
value = 1.0
anchor = .center
}
vScale = value
hScale = 2 - sqrt(value)
self.yOffset = yOffset
self.anchor = anchor
}
.onEnded { _ in
isTouching = false
vScale = 1.0
hScale = 1.0
anchor = .center
yOffset = 0.0
})
}
.animation(isTouching ? .none : .smooth(duration: 0.5), value: vScale)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
@ViewBuilder
var wallpaper: some View {
Image("wallpaper")
.resizable()
.padding(-40)
.ignoresSafeArea()
.blur(radius: 40)
}
@ViewBuilder
var slider: some View {
ZStack {
Rectangle()
.background(.ultraThickMaterial)
VStack {
Spacer()
.frame(minHeight: 0)
Rectangle()
.frame(width: Const.shapeSize.width, height: value * Const.shapeSize.height)
.foregroundColor(Color(uiColor: .systemGray5))
}
}
}
}
#Preview {
RubberBandSwitch()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment