scrollview中的SwiftUI动画/过渡看起来很奇怪

问题描述 投票:1回答:1

我在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,则动画不会在出现时播放,这很好,但是我必须使用scrollview。因此,对我而言,最好的解决方案是保留用于打开文本的动画,但是在视图出现时以某种方式将其删除。

ios swift animation swiftui scrollview
1个回答
0
投票

这里是可能的解决方案。另请阅读内联注释。经过Xcode 11.4 / iSO 13.4测试]

demo

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
            }
        }
    }
}
    
© www.soinside.com 2019 - 2024. All rights reserved.