Переходы SwiftUI условных дочерних представлений

Я пытаюсь понять и поэкспериментировать с переходами между представлениями swiftUI и мог бы немного понять, почему следующее работает не так, как я ожидал:

struct ContentView: View {
@State private var showOverlay: Bool = false

var body: some View {
    ZStack {
        VStack {
            Button(action: {
                withAnimation(.easeInOut) {
                    self.showOverlay = true
                }
            }) {
                Text("Hello, World!")
            }
        }
        .zIndex(0)
        .animation(nil)
        .blur(radius: showOverlay ? 3 : 0)

        if showOverlay {
            HStack {
                Button(action: {
                    withAnimation(.easeInOut) {
                        self.showOverlay = false
                    }
                }) {
                    Text("Close")
                }
                .frame(width: 80, height: 80)
                .background(Color.red)
                .transition(.move(edge: .top))

                Button(action: {
                    withAnimation(.easeInOut) {
                        self.showOverlay = false
                    }
                }) {
                    Text("Close")
                }
                .frame(width: 80, height: 80)
                .background(Color.red)
                .transition(.move(edge: .bottom))
            }
            .zIndex(1.0)
        }
    }
}

Есть условный HStack из двух кнопок. Когда параметр @StateshowOverlay изменено это сделано в течение withAnimationблок. Переходы на отдельных кнопках не соблюдаются.

Если я удалю HStack и помещу zIndex(1) на каждую кнопку, то произойдет переход удаления, но не переход вставки.

Я хочу, чтобы обе кнопки переходили определенным образом, когда их группа добавляется в представление.

Вопросы: почему обертывание в HStack приводит к игнорированию внутренних переходов? Почему краевой переход работает только в одном направлении?

2 ответа

Чтобы получить две разные анимации, вы можете подтянуть условную логику ближе к кнопкам, то есть внутри HStack:

HStack {
  if showOverlay {
    Button(action: {
      withAnimation(.easeInOut) {
        self.showOverlay = false
      }
    }) {
      Text("Close")
    }
    .frame(width: 80, height: 80)
    .background(Color.red)
    .transition(.move(edge: .top))

    Button(action: {
      withAnimation(.easeInOut) {
        self.showOverlay = false
      }
    }) {
      Text("Close")
    }
    .frame(width: 80, height: 80)
    .background(Color.red)
    .transition(.move(edge: .bottom))
  }
}
.zIndex(1.0)

Это оставляет вас с пустым HStack когда showOverlay == false, но это не должно быть большой проблемой, по крайней мере, в этом примере.

Переход работает для вида, который появился / исчез. В предоставленном коде снимок появился / исчезHStack, поэтому к нему следует применить переход.

Примечание: переходы необходимо тестировать на симуляторе или реальном устройстве, большинство из них не работают в предварительном просмотре.

Ниже представлена ​​измененная часть кода, которая дает рабочее поведение. Протестировано с Xcode 11.2 / iOS 13.2

введите описание изображения здесь

if showOverlay {
    HStack {
        Button(action: {
            withAnimation(.easeInOut) {
                self.showOverlay = false
            }
        }) {
            Text("Close")
        }
        .frame(width: 80, height: 80)
        .background(Color.red)

        Button(action: {
            withAnimation(.easeInOut) {
                self.showOverlay = false
            }
        }) {
            Text("Close")
        }
        .frame(width: 80, height: 80)
        .background(Color.red)
    }
    .transition(.move(edge: .top)) // << only in this place needed
    .zIndex(1.0)
}
Другие вопросы по тегам