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)
}
}
}
и прочтите это: