Card Style Sliding Menu from Bottom
Published by @SoNiceInfo at 5/26/2020
Introducing how to create card style slide menu up frome below witch is simillar to the Map and Google App.
Not only my implementation, but also packages published on GitHub.
They are easily used by adding "Swift Pakckages" in Xcode.
I'll create the menu on the map at this time.
Prepare ContentView
First, make a view to display a map.
Detail of creating map in SwiftUI is introduced at Display Map
Call MapView from ContentView
. In advance call CardModalView
which is crated at next step.
import SwiftUI
struct ContentView: View {
var body: some View {
ZStack() {
MapView()
CardModalView()
}
}
}
Implement card style menu
This card style menu stops at top, middle and bottom.
Override the offsets
at onAppear
from GeometryReader to fit with screen size. onChanged
in DragGesture
allows you to slide while restricting the top and bottom areas to stay in the same area while moving. onEnded
is written in a case-by-case manner so that the card style sliding menu is set to the top, middle, and bottom regions close to each other.
import SwiftUI
struct CardModalView: View {
@State private var offsets = (top: CGFloat.zero, middle: CGFloat.zero, bottom: CGFloat.zero)
@State private var offset: CGFloat = .zero
@State private var lastOffset: CGFloat = .zero
var body: some View {
GeometryReader { geometry in
VStack (spacing: 30) {
RoundedRectangle(cornerRadius: 5)
.foregroundColor(.gray)
.frame(width: 100, height: 10)
Text("CardModal")
.font(.largeTitle)
Spacer()
}
.padding()
.frame(width: geometry.size.width, height: geometry.size.height)
.background(Color.yellow)
.clipShape(RoundedRectangle(cornerRadius: min(self.offset, 20) ))
.animation(.interactiveSpring())
.onAppear {
self.offsets = (
top: .zero,
middle: geometry.size.height / 2,
bottom: geometry.size.height * 3 / 4
)
self.offset = self.offsets.bottom
self.lastOffset = self.offset
}
.offset(y: self.offset)
.gesture(DragGesture(minimumDistance: 5)
.onChanged { v in
let newOffset = self.lastOffset + v.translation.height
if (newOffset > self.offsets.top && newOffset < self.offsets.bottom) {
self.offset = newOffset
}
}
.onEnded{ v in
if (self.lastOffset == self.offsets.top && v.translation.height > 0) {
if (v.translation.height < geometry.size.height / 2) {
self.offset = self.offsets.middle
} else {
self.offset = self.offsets.bottom
}
} else if (self.lastOffset == self.offsets.middle) {
if (v.translation.height < 0) {
self.offset = self.offsets.top
} else {
self.offset = self.offsets.bottom
}
} else if (self.lastOffset == self.offsets.bottom && v.translation.height < 0) {
if (abs(v.translation.height) > geometry.size.height / 2) {
self.offset = self.offsets.top
} else {
self.offset = self.offsets.middle
}
}
self.lastOffset = self.offset
}
)
}
.edgesIgnoringSafeArea(.all)
}
}
struct CardModalView_Previews: PreviewProvider {
static var previews: some View {
CardModalView()
}
}
Use Swift Packages
Swift Packages bring various functions to your app.https://github.com/moifort/swiftUI-slide-over-card are recommended. In Xcode, Select [Project] [PROJECT_NAME] [Swift Packages] then add URL above with [+] button. Here is a usage of the package.
import SwiftUI
import SlideOverCard
struct ContentView: View {
@State private var position = CardPosition.bottom
@State private var background = BackgroundStyle.solid
var body: some View {
ZStack() {
MapView()
SlideOverCard($position, backgroundStyle: $background) {
VStack {
Text("Slide Over Card").font(.title)
Spacer()
}
}
}
}
}
References
moifort/swiftUI-slide-over-card: Slide over modal/card for SwiftUIP.S.
How to create sliding menu comming from top, left and right.
Sliding Menu from Top, Left and Right