SwiftUI:动画偏移以从屏幕外滑入

SwiftUI: Animate offset to slide in from off screen

我正在尝试在其父视图底部的视图中设置动画。通过设置偏移动画可以相对容易地做到这一点,如下所示:

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()
    }
}

明显的问题是,这只是使用任意值作为动画偏移量,当考虑动态类型时,这很快就会中断

我的问题是:

有没有办法正确确定 BannerView 的高度以正确调整此动画。或者有没有更好的方法可以达到这个效果?

谢谢大家

只需过渡即可完成,例如

测试 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()
    }
}

如果要确定 BannerView() 的高度,可以使用 GeometryReader。我创建了 BannerView() 例如下面的例子:-

   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)
        }
   }

因此,Binding 值将为您的 MainView() 提供 bannerView 的高度。您可以使用它来确定您的偏移量。

   @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()
    }

希望你觉得这有用。