'SwiftUI: Animate offset to slide in from off screen
I'm trying to animate in a view the bottom of its parent view. This is relatively easy to do by animating the offset, like so:
struct ContentView: View {
@State var isShowingBanner = true
var bannerOffset: CGFloat {
isShowingBanner ? 0 : 60
}
var body: some View {
VStack {
VStack {
Spacer()
BannerView()
.offset(y: bannerOffset)
}
.border(Color.black, width: 1.0)
.clipped()
Spacer()
Button("Toggle Banner") {
withAnimation {
isShowingBanner.toggle()
}
}
}
.padding()
}
}
The glaringly obvious problem is that this just uses an arbitrary value for the animated offset, and this quickly breaks when considering dynamic type
My question is:
Is there a way to properly determine the height of BannerView
to correctly adjust this animation. Or is there a better way to achieve this effect?
Thanks all
Solution 1:[1]
It can be done just with transition, like
Tested with Xcode 13.3 / iOS 15.4
struct ContentView: View {
@State var isShowingBanner = true
var body: some View {
VStack {
VStack {
Spacer()
if isShowingBanner {
BannerView()
.transition(.move(edge: .bottom)) // << here !!
}
}
// >> empty container should not shrink !!
.frame(maxWidth: .infinity, maxHeight: .infinity)
.border(Color.black, width: 1.0)
.clipped()
Spacer()
Button("Toggle Banner") {
withAnimation {
isShowingBanner.toggle()
}
}
}
.padding()
}
}
Solution 2:[2]
If you want to determine the Height of the BannerView() You can use GeometryReader. I have created BannerView() Just for example bellow : -
struct BannerView() : View {
@Binding var height : CGFloat
var body: some View {
VStack{
GeometryReader { proxy in
Rectangle().fill(.green).onAppear {
height = proxy.size.height
}
}
}.frame(height : 100)
}
}
So, the Binding value will provide height of the bannerView to your MainView(). You can use that to determine your offset.
@State var isShowingBanner = true
@State var offsetHeight : CGFloat = 0
var body: some View {
VStack {
VStack {
Spacer()
BannerView(height: $offsetHeight)
.offset(y: isShowingBanner ? 0 : offsetHeight)
}
.border(Color.black, width: 1.0)
.clipped()
Spacer()
Button("Toggle Banner") {
withAnimation {
isShowingBanner.toggle()
}
}
}
.padding()
}
Hope you found this useful.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Asperi |
Solution 2 | Namra Parmar |