我该如何反转SwiftUI动画中的幻灯片过渡效果?

19

我正在处理一系列屏幕的设计,应在按下按钮时更改,并应从右到左滑入/滑出。
一切都运行得很好,除了.slide转换会使其从前沿移动,并向后沿移动。 (从左到右)
我想颠倒转换动画方向,而不改变前导/尾随是什么(至少不在整个应用程序的上下文中)。

我尝试将转换更改为.move(edge: .trailing),但视图将从相同的方向移动进入和移出。

import SwiftUI

struct ContentView: View {
    enum screens {
        case start, mid, final
    }
    @State var curScreen: screens = .start
    
    func changeScreen() {
        switch curScreen {
        case .start:
            curScreen = .mid
        case .mid:
            curScreen = .final
        case .final:
            return
        }
    }
    
    var body: some View {
        switch curScreen {
        case .start:
            ScreenView(callback: changeScreen, text: "Start")
                .transition(.slide)
        case .mid:
            ScreenView(callback: changeScreen, text: "Mid")
                .transition(.slide)
        case .final:
            ScreenView(callback: {}, text: "Final")
                .transition(.slide)
        }
    }
}

struct ScreenView: View {
    let callback: () -> ()
    let text: String
    var body: some View {
        Text(text)
            .padding()
            .frame(maxWidth: .infinity)
            .onTapGesture {
                withAnimation(.default) {
                    callback()
                }
            }
    }
}

3
这个回答是否解答了你的问题:https://dev59.com/Db3pa4cB1Zd3GeqPYCLc#63782921? - Asperi
@Asperi 是的,它可以!非常感谢你! - noranraskin
1
这个回答解决了你的问题吗?SwiftUI如何实现下一页和上一页的动画效果? - Pranav Kasetti
2个回答

35

@Asperi 已回答了我的问题,但是当我搜索时它没有出现在Google或StackOverflow上,所以算法如下:

如何在SwiftUI中反转滑动转换:

参考自Apple Developer文档:

static var slide: AnyTransition
// A transition that inserts by moving in from the leading edge, and removes by moving out towards the trailing edge.

也可以写作:

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

所以,要反转动画只需翻转 insertionremoval 并将其放在你的过渡 ViewModifier 中。

由于我需要多次使用它,所以我制作了一个扩展到 AnyTransition 的工具,这样我就可以直接调用 .transition(.backslide) 了。

extension AnyTransition {
    static var backslide: AnyTransition {
        AnyTransition.asymmetric(
            insertion: .move(edge: .trailing),
            removal: .move(edge: .leading))}
}

1
是的,在只往前走的情况下可以行得通。谢谢。但是在我的示例中,用户可以选择在同一屏幕上向后或向前。在这种情况下,我根据用户的操作设置回退转换或简单滑动。更改后它不起作用了。似乎之前已经设置了“删除”过渡,并且不能随时更改。已将相同的评论添加到https://dev59.com/Db3pa4cB1Zd3GeqPYCLc。也许您有处理它的想法。谢谢 - Sander

1

适用于iOS 16

 Group {
                    switch viewModel.selectedTab {
                        case .travel:
                            TravelSearchForm(viewModel: viewModel)
                        case .cars:
                            CarsSearchForm(viewModel: viewModel.carsForm)
                        case .rooms:
                            RoomsSearchForm(viewModel: viewModel.roomsForm)
                    }
                }
                .transition(.dynamicSlide(forward: $viewModel.tabTransitionDirectionIsForward))
                .animation(.default, value: viewModel.selectedTab)

extension AnyTransition {

    struct SlideModifier: ViewModifier {
        let width: CGFloat
        @Binding var forward: Bool

        func body(content: Content) -> some View {
            content
                .offset(x: (forward ? 1 : -1) * width)
        }
    }

    static func dynamicSlide(forward: Binding<Bool>) -> AnyTransition {
        .asymmetric(
            insertion: .modifier(
                active: SlideModifier(width: UIScreen.main.bounds.width, forward: forward),
                identity: SlideModifier(width: 0, forward: .constant(true))
            ),

            removal: .modifier(
                active: SlideModifier(width: -UIScreen.main.bounds.width, forward: forward),
                identity: SlideModifier(width: 0, forward: .constant(true))
            )
        )
    }
}

dinamicSlide是什么? - Nikita Ermolenko
嘿,忘记加上最有趣的部分了),已修复 - Dmih

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接