SwiftUI: анимация переходов
Как анимировать переходы между слайдами между разными представлениями?
В следующем примере кода я создал средство выбора, которое выбирает, какое представление отображать, и моя цель — получить переход, похожий на переход NavigationLink. На данный момент он вообще не анимируется. Если я добавлю
.animation(.easeInOut(duration: 2))
модификатор к
ZStack
он анимирует анимацию затухания в течение 2 секунд, но я не понимаю, почему.
struct ContentView: View {
enum WhichScreen: String, CaseIterable {
case red, blue, green, yellow
}
@State private var whichScreen = WhichScreen.red
var body: some View {
VStack {
Picker("screen", selection: $whichScreen.animation()) {
ForEach(WhichScreen.allCases, id: \.self) { value in
Text(value.rawValue).tag(value)
}
}
.pickerStyle(SegmentedPickerStyle())
ZStack {
Color.black
switch whichScreen {
case .red:
Color.red
case .blue:
Color.blue
case .green:
Color.green
case .yellow:
Color.yellow
}
}
.transition(.slide)
}
}
}
2 ответа
Вам действительно нужен ZStack с черным цветом (который никогда не отображается в вашем фрагменте примера)? Без него переход работает из коробки (в симуляторе, а не в превью SwiftUI):
struct ContentView: View {
enum WhichScreen: String, CaseIterable {
case red, blue, green, yellow
}
@State private var whichScreen = WhichScreen.red
var body: some View {
VStack {
Picker("screen", selection: $whichScreen.animation()) {
ForEach(WhichScreen.allCases, id: \.self) { value in
Text(value.rawValue).tag(value)
}
}
.pickerStyle(SegmentedPickerStyle())
Group {
switch whichScreen {
case .red:
Color.red
case .blue:
Color.blue
case .green:
Color.green
case .yellow:
Color.yellow
}
}
.transition(.slide)
}
}
}
Чтобы получить нужную анимацию слайдов,
.transition
необходимо применить только к той части, которую вы хотите скользить (например, в этом случае не черные цвета):
ZStack {
Color.black
Group {
switch whichScreen {
case .red:
Color.red
case .blue:
Color.blue
case .green:
Color.green
case .yellow:
Color.yellow
}
}.transition(.slide)
}
У вас все еще есть еще один шаг, о котором нужно позаботиться, если вы хотите, чтобы он был точно таким же, как
NavigationLink
переход, который заключается в том, что прямо сейчас «старый» или «предыдущий» вид исчезает перед переходом. Если вы хотите, чтобы это было включено в стек, вы можете сделать что-то вроде этого:
struct ContentView: View {
enum WhichScreen: String, CaseIterable {
case red, blue, green, yellow
}
@State private var whichScreen = WhichScreen.red
@State private var previousScreen : WhichScreen? = .none
var body: some View {
VStack {
Picker("screen", selection: $whichScreen.animation()) {
ForEach(WhichScreen.allCases, id: \.self) { value in
Text(value.rawValue).tag(value)
}
}
.pickerStyle(SegmentedPickerStyle())
.onChange(of: whichScreen) { [whichScreen] _ in
previousScreen = whichScreen
}
ZStack {
Color.black
if let previousScreen = previousScreen {
switch(previousScreen) {
case .red:
Color.red
case .blue:
Color.blue
case .green:
Color.green
case .yellow:
Color.yellow
}
}
Group {
switch whichScreen {
case .red:
Color.red
case .blue:
Color.blue
case .green:
Color.green
case .yellow:
Color.yellow
}
}.transition(.slide)
}
}
}
}