Skip to content

Instantly share code, notes, and snippets.

@yimajo
Created January 30, 2021 07:36
Show Gist options
  • Save yimajo/3ddc55efa70f1571406784623a3f4ab2 to your computer and use it in GitHub Desktop.
Save yimajo/3ddc55efa70f1571406784623a3f4ab2 to your computer and use it in GitHub Desktop.
SwiftUIでハーフモーダル的なものを出す
import SwiftUI
struct ContentView: View {
var body: some View {
ZStack(alignment: .top) {
MapView()
SlideOverCard {
VStack {
Text("Half Modal")
.font(.headline)
.foregroundColor(Color.white)
Spacer()
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
.frame(height: 800)
.padding(.horizontal, 10.0)
}
.edgesIgnoringSafeArea(.vertical)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct SlideOverCard<Content: View> : View {
@GestureState private var dragState = DragState.inactive
@State var position = CardPosition.top
var content: () -> Content
var body: some View {
let drag = DragGesture()
.updating($dragState) { drag, state, transaction in
state = .dragging(translation: drag.translation)
}
.onEnded(onDragEnded)
return Group {
VStack {
Handle()
.background(Color.clear)
self.content()
}
}
.background(Color(#colorLiteral(red: 0.2549019754, green: 0.2745098174, blue: 0.3019607961, alpha: 1)))
.cornerRadius(10.0)
.shadow(color: Color(.sRGBLinear, white: 0, opacity: 0.13), radius: 10.0)
.offset(y: position.rawValue + dragState.translation.height)
.animation(dragState.isDragging ? nil : .interpolatingSpring(stiffness: 300.0, damping: 30.0, initialVelocity: 10.0))
.opacity(0.5)
.gesture(drag)
}
private func onDragEnded(drag: DragGesture.Value) {
let verticalDirection = drag.predictedEndLocation.y - drag.location.y
let cardTopEdgeLocation = self.position.rawValue + drag.translation.height
let positionAbove: CardPosition
let positionBelow: CardPosition
let closestPosition: CardPosition
if cardTopEdgeLocation <= CardPosition.middle.rawValue {
positionAbove = .top
positionBelow = .middle
} else {
positionAbove = .middle
positionBelow = .bottom
}
if (cardTopEdgeLocation - positionAbove.rawValue) < (positionBelow.rawValue - cardTopEdgeLocation) {
closestPosition = positionAbove
} else {
closestPosition = positionBelow
}
if verticalDirection > 0 {
self.position = positionBelow
} else if verticalDirection < 0 {
self.position = positionAbove
} else {
self.position = closestPosition
}
}
}
enum CardPosition: CGFloat {
case top = 100
case middle = 500
case bottom = 850
}
enum DragState {
case inactive
case dragging(translation: CGSize)
var translation: CGSize {
switch self {
case .inactive:
return .zero
case .dragging(let translation):
return translation
}
}
var isDragging: Bool {
switch self {
case .inactive:
return false
case .dragging:
return true
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment