SwiftUI: dynamiczna zmiana przejścia widoku po utworzeniu widoku

Aug 16 2020

Chcę dynamicznie zmienić przejście widoku po utworzeniu widoku. Przełączam zmienną stanu isTransition1, klikając przycisk, aby przełączać się między transition1i transition2jak poniżej. Jednak nie działa zgodnie z przeznaczeniem, jeśli jednym z tych przejść jest krycie. Widok, który ma zostać usunięty natychmiast po zmianie przejścia, zawsze zachowuje oryginalne przejście. O dziwo, jeśli przestawię się transition2na suwak, będzie działać bez problemu. Widok, który ma zostać usunięty, użyje nowego przejścia. Czy jest jakiś sposób, aby krycie działało tutaj?

let transition1 = AnyTransition.asymmetric(insertion: .move(edge: .trailing),
                                           removal: .move(edge: .leading))

let transition2 = AnyTransition.opacity

struct Wrapper1<Content: View>: View {
  let content: Content

  var body: some View {
    content
  }
}

struct Wrapper2<Content: View>: View {
  let content: Content

  var body: some View {
    content
  }
}

struct TextView: View {
  let count: Int
  let color: Color

  var body: some View {
    ZStack {
      color
        .edgesIgnoringSafeArea(.all)
        .frame(maxWidth: UIScreen.main.bounds.width,
               maxHeight: UIScreen.main.bounds.height)

      Text("Count: \(count)")
        .font(.title)
        .offset(y: -200)
    }
  }
}

struct ContentView: View {
  @State private var count = 0
  @State private var isTransition1 = false

  var body: some View {
    ZStack {
      if count % 2 == 0 {
        Wrapper1(content: TextView(count: count, color: Color.green)
          .transition(isTransition1 ? transition1 : transition2))
        } else {
          Wrapper2(content: TextView(count: count, color: Color.red)
            .transition(isTransition1 ? transition1 : transition2))
        }

      HStack(spacing: 100) {
        Button(action: {
          self.isTransition1.toggle()
        }) {
          Text("Toggle Transition").font(.title)
        }

        Button(action: {
          withAnimation(.linear(duration: 2)) {
            self.count += 1
          }
        }) {
          Text("Increase").font(.title)
        }
      }
    }
  }
}

Odpowiedzi

1 Asperi Aug 16 2020 at 11:44

Nie jestem pewien, czy dobrze zrozumiałem, jaki efekt próbowałeś osiągnąć, ale spróbuj zresetować hierarchię widoków (przynajmniej to zdecydowanie resetuje przejścia, więc nie wpływają na siebie):

  var body: some View {
    ZStack {
      if count % 2 == 0 {
        Wrapper1(content: TextView(count: count, color: Color.green)
          .transition(isTransition1 ? transition1 : transition2))
        } else {
          Wrapper2(content: TextView(count: count, color: Color.red)
            .transition(isTransition1 ? transition1 : transition2))
        }

      HStack(spacing: 100) {
        Button(action: {
          self.isTransition1.toggle()
        }) {
          Text("Toggle Transition").font(.title)
        }

        Button(action: {
          withAnimation(.linear(duration: 2)) {
            self.count += 1
          }
        }) {
          Text("Increase").font(.title)
        }
      }
    }.id(isTransition1)     // << here !!
  }