SwiftUI - анимация прозрачности вида в ZStack с помощью .easeInOut

У меня есть представление, расположенное поверх mapView (в ZStack), и я хочу, чтобы зеленый, верхний вид появлялся и исчезал с .easeInOutМодификатор анимации применяется к непрозрачности вида. Как вы можете видеть на гифке, он красиво исчезает, но исчезает внезапно.

Если я удалю 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, но мне не удалось найти предыдущую ссылку.

2 ответа

Решение

Вот рабочее решение. Протестировано с 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)
    }
}

Попробуйте это: -> только что добавил zIndex ... все остальное то же самое

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

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

и прочтите это:

Анимация перехода не работает в SwiftUI

Другие вопросы по тегам