首页 > 解决方案 > SwiftUI - 使用 .easeInOut 为 ZStack 中的视图不透明度设置动画

问题描述

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

在此处输入图像描述

如果我删除 mapView 那么一切都很好。如果我用简单的 mapView 替换,Rectangle()那么问题就会返回,所以我相信它与 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))
    }
}

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

.transition(.opacity)

并将按钮代码更改为:

Button("Animate") {
    withAnimation(.easeInOut(duration: 1.0)) {
        self.show.toggle()
    }
}

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

标签: animationswiftuiopacityzstackeaseinout

解决方案


这是工作解决方案。使用 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)
        }
    }

另一个替代方案,实际上具有相同的视觉效果是嵌入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)
    }
}

推荐阅读