SwiftUI - 使用 .easeInOut 为 ZStack 中的视图不透明度设置动画

Mag*_*nas -2 animation opacity swiftui zstack easeinout

我有一个位于 mapView 顶部的视图(在 ZStack 中),并且希望能够通过将.easeInOut动画修改器应用于视图的不透明度来淡入和淡出绿色的上视图。正如您在 gif 中看到的那样,它很好地淡入但突然消失了。

在此处输入图片说明

如果我删除 mapView 那么一切都很好。如果我用一个简单的替换 mapViewRectangle()那么问题又回来了,所以我相信它与 ZStack 而不是地图有关。有趣的是,我实际上使用的是 Mapbox 而不是 MapKit(为了简单起见,如下面的代码所示)并且淡入淡出/突然消失的行为被逆转了。

import SwiftUI
import MapKit

struct ContentView: View {
    @State private var show = false

    var body: some View {
        VStack {
            ZStack {
                MapView()
                if show {
                    LabelView()
                        .transition(AnyTransition.opacity.animation(.easeInOut(duration: 1.0)))
                }
            }
            Button("Animate") {
                self.show.toggle()
            }.padding(20)
        }
    }
}

struct MapView: UIViewRepresentable {
    func makeUIView(context: Context) -> MKMapView {
        let mapView = MKMapView()
        mapView.mapType = .standard
        return mapView
    }

    func updateUIView(_ uiView: MKMapView, context: Context) { }
}

struct LabelView: View {
    var body: some View {
        Text("Hi there!")
            .padding(10)
            .font(.title)
            .foregroundColor(.white)
            .background(RoundedRectangle(cornerRadius: 8).fill(Color.green).shadow(color: .gray, radius: 3))
    }
}
Run Code Online (Sandbox Code Playgroud)

我尝试使用替代动画代码,将LabelView过渡替换为:

.transition(.opacity)
Run Code Online (Sandbox Code Playgroud)

并将按钮代码更改为:

Button("Animate") {
    withAnimation(.easeInOut(duration: 1.0)) {
        self.show.toggle()
    }
}
Run Code Online (Sandbox Code Playgroud)

但每次都会出现相同的行为。我猜这是一个 SwiftUI 错误,但找不到任何以前的参考。

Asp*_*eri 6

这是工作解决方案。使用 Xcode 11.4 / iOS 13.4 测试。

演示

正如在演示中看到的,透明标签的存在不会影响地图视图的功能。

    var body: some View {
        VStack {
            ZStack {
                MapView()
                LabelView().opacity(show ? 1 : 0)   // here !!
            }.animation(.easeInOut(duration: 1.0))

            Button("Animate") {
                self.show.toggle()
            }.padding(20)
        }
    }
Run Code Online (Sandbox Code Playgroud)

另一种替代方法,实际上具有相同的视觉效果是嵌入LabelView到容器中并对其应用过渡(必须留下一些东西才能使视图消失)

var body: some View {
    VStack {
        ZStack {
            MapView()
            VStack {              // << here !!
                if show {
                    LabelView()
                }
            }.transition(.opacity).animation(.easeInOut(duration: 1.0))
        }
        Button("Animate") {
            self.show.toggle()
        }.padding(20)
    }
}
Run Code Online (Sandbox Code Playgroud)