I'm doing a Map based app with SwiftUI and I need to change the height of modal Card (this is a view where the map info will be located) via dragging it up/down, like in Apple Maps.
Here is the screenshot of Card which height Im trying to interact with https://i.sstatic.net/mZX2m.png
I've implemented a ZStack
with RoundedRectangle
and added a DragGesture()
modifier.
ZStack(alignment: .top){
RoundedRectangle(cornerRadius: 16.0)
.frame(height:currentHeight)
Text("Card")
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color.white)
.multilineTextAlignment(.center)
.padding(.top)
}.gesture(DragGesture()
.onChanged { value in
if (self.currentHeight + value.predictedEndLocation.y - value.startLocation.y > UIScreen.main.bounds.height) {
self.currentHeight = UIScreen.main.bounds.height
} else {
self.currentHeight += value.predictedEndLocation.y - value.startLocation.y
}
}
.onEnded { value in
if (self.currentHeight + value.predictedEndLocation.y - value.startLocation.y > UIScreen.main.bounds.height) {
self.currentHeight = UIScreen.main.bounds.height
} else {
self.currentHeight += value.predictedEndLocation.y - value.startLocation.y
}
})
The first problem was with dragging up, the card went over screen height and Im checking for UIScreen bounds height to prevent height being bigger than screen, but there are more problems with calculations, Card's height gets ambiguous very fast and it doesn't want to drag down.
I have never worked with gesture recognizers. Can you tell me the correct way of calculations?
Here is an approach (some helpful comments in code below)
struct TestResizingCard: View {
static let kMinHeight: CGFloat = 100.0
@State var currentHeight: CGFloat = kMinHeight // << any initial
var body: some View {
GeometryReader { g in // << for top container height limit
ZStack(alignment: .bottom) {
Rectangle().fill(Color.yellow) // << just for demo
self.card()
.gesture(DragGesture()
.onChanged { value in
// as card is at bottom the offset is reversed
let newHeight = self.currentHeight - (value.location.y - value.startLocation.y)
if newHeight > Self.kMinHeight && newHeight < g.size.height {
self.currentHeight = newHeight
}
})
}
}
}
func card() -> some View {
ZStack(alignment: .top){
RoundedRectangle(cornerRadius: 16.0)
.frame(height:currentHeight)
Text("Card")
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color.white)
.multilineTextAlignment(.center)
.padding(.top)
}
}
}
struct TestResizingCard_Previews: PreviewProvider {
static var previews: some View {
TestResizingCard()
}
}