滚动视图中的 SwiftUI 动画/过渡表现奇怪

Posted

技术标签:

【中文标题】滚动视图中的 SwiftUI 动画/过渡表现奇怪【英文标题】:SwiftUI animation/transition within scrollview behaving strange 【发布时间】:2020-05-09 14:18:47 【问题描述】:

我在 SwiftUI 中有一个带有多个元素的 ScrollView,其中一些元素在点击时会展开。

struct ExpandingView: View 

    @State var showContent = false

    var body: some View 
        VStack 
            HStack 
                Button(action: withAnimation 
                        self.showContent.toggle()
                    
                ) 
                    Image(systemName: "chevron.right.circle")
                
                Text("TITLE")
                    .padding(.leading, 10)
                Spacer()
            
            if showContent 
                Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras volutpat dapibus ante eget laoreet. Aenean lacus elit, auctor ut nisl id, fermentum pretium mi. Quisque lacus nisl, suscipit hendrerit est sed, congue dictum augue. Suspendisse semper viverra accumsan. Maecenas commodo turpis convallis nisl bibendum pharetra.")
                    .transition(AnyTransition.move(edge: .top).combined(with: .opacity))
            
        
    


struct Test: View 

    var body: some View 
        ScrollView 
            ExpandingView()
            ExpandingView()
            ExpandingView()
            Text("Some static text")
        
    

如果您尝试打开其中一个展开的文本,您会发现过渡并不顺畅,有点像跳跃,然后过渡开始。

https://media.giphy.com/media/cjhClEVwgsEQpkBGAv/giphy.gif

所以这是我尝试过的:

如果我删除滚动视图并将其放到 VStack 中,例如它可以正常工作,但这不是一个选项,因为我有更多的元素无法显示在屏幕上。 我尝试为滚动视图设置动画,因为我读到它可以解决此类问题,如下所示:
ScrollView 
            ExpandingView()
            ExpandingView()
            ExpandingView()
            Text("Some static text")
        .animation(.spring())

它在打开过渡方面工作得很好,它甚至看起来更好用弹簧效果,但整个滚动视图的弹簧动画在视图出现时播放,这是我不想要的。

https://media.giphy.com/media/lTMG9mGD0X0qrksYtB/giphy.gif

同样,如果我将 ScrollView 更改为 VStack,动画不会在出现时播放,这很好,但我必须使用滚动视图。所以对我来说最好的解决方案是保留打开文本的动画,但在视图出现时以某种方式将其删除。

【问题讨论】:

【参考方案1】:

这是可能的解决方案。另请阅读 cmets inline。使用 Xcode 11.4 / ISO 13.4 测试

struct ExpandingView: View 

    @State var showContent = false

    var body: some View 
        VStack 
            HStack 
                Button(action: 
                        self.showContent.toggle()
                ) 
                    Image(systemName: "chevron.right.circle")
                
                Text("TITLE")
                    .padding(.leading, 10)
                Spacer()
            
            if showContent 
                Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras volutpat dapibus ante eget laoreet. Aenean lacus elit, auctor ut nisl id, fermentum pretium mi. Quisque lacus nisl, suscipit hendrerit est sed, congue dictum augue. Suspendisse semper viverra accumsan. Maecenas commodo turpis convallis nisl bibendum pharetra.")
                    .fixedSize(horizontal: false, vertical: true)
                    .transition(AnyTransition.move(edge: .top).combined(with: .opacity))
            
        
    


struct DemoExpandingView: View 

    // initial nil to avoid initial animation
    @State private var animation: Animation? = nil
    var body: some View 
        ScrollView 
            VStack 
                ExpandingView()
                ExpandingView()
                ExpandingView()
                Text("Some static text")
            .animation(animation) // << needed to animate static section
        
        .onAppear 
            DispatchQueue.main.async 
                // assign in-container animation `after` container rendered
                self.animation = .default
            
        
    

【讨论】:

以上是关于滚动视图中的 SwiftUI 动画/过渡表现奇怪的主要内容,如果未能解决你的问题,请参考以下文章

NavigationView中的SwiftUI自定义动画过渡?

在 SwiftUI 中将视图添加到层​​次结构时如何动画过渡

SwiftUI - 动画过渡

SwiftUI:动画过渡

SwiftUI4.0有趣的动画升级:新iOS16视图内容过渡动画

SwiftUI4.0有趣的动画升级:新iOS16视图内容过渡动画