LazyVStack scrolling stops animations

[亡魂溺海] 提交于 2021-01-29 07:51:01

问题


This code lists 100 rows with refresh icon animations. When using a LazyVStack instead of a VStack, after scrolling down to the bottom of this list all the animations stop, including those at the top of the list once you scroll back. No such issues with a VStack. Any ideas as to why this is happening and is there a workaround? Using Xcode 12.0.1, iOS 14, Swift 5

struct RefreshingList : View {
    @State var isAnimating = false

    var body: some View {
        ScrollView {
            LazyVStack { // <- change to VStack to have animations not stop
                ForEach(0..<100, id: \.self) { i in
                    HStack {
                        Text("\(i) -> ")
                        self.button()
                    }
                }
            }
        }
        .onAppear {
            self.isAnimating=true
        }
    }
    
    func button() -> some View {
        Button(action: {}, label: {
            Image(systemName: "arrow.2.circlepath")
                .rotationEffect(Angle(degrees: self.isAnimating ? 360.0 : 0.0))
                .animation(Animation.linear(duration: 2.0)
                            .repeatForever(autoreverses: false))
        })
    }
}

回答1:


Animation happens when a change to a view on screen is observed. In the VStack all of the views are created immediately so SwiftUI is able to observe the change in rotation value for all views.

In the LazyVStack case, the views are only created as needed, so the bottom ones aren't on screen when the rotation value changes in .onAppear. When they do appear on screen, it is with the already changed value, so no animation happens.

One way to fix this is to let the buttons own the .isAnimating @State variable. Then anytime one is created, it will be animating.

struct RefreshingList : View {

    var body: some View {
        ScrollView {
            LazyVStack {
                ForEach(0..<100, id: \.self) { i in
                    HStack {
                        Text("\(i) -> ")
                        AnimatedButton()
                    }
                }
            }
        }
    }
}

struct AnimatedButton: View {
    @State var isAnimating = false
    
    var body: some View {
        Button(action: {
            
        }, label: {
            Image(systemName: "arrow.2.circlepath")
                .rotationEffect(Angle(degrees: self.isAnimating ? 360.0 : 0.0))
                .animation(Animation.linear(duration: 2.0)
                            .repeatForever(autoreverses: false))
        })
        .onAppear {
            isAnimating = true
        }
    }
}



回答2:


struct RefreshingListView: View {
    var body: some View {
        ScrollView {
            LazyVStack {
                ForEach(0..<100) {
                    LabelView(id: $0)
                        .id($0)
                }
            }
            .animation(
                Animation
                    .linear(
                        duration: 2)
                    .repeatForever(
                        autoreverses: false))

        }
    }
}

struct LabelView: View {
    @State var
        animate = false
    var id: Int
    var body: some View {
        Label(
            title: {
                Text("<- \(id)")
            }, icon: {
                Image(
                    systemName:
                        "arrow.2.circlepath")
                    .foregroundColor(.blue)
                    .padding(.horizontal)
                    .rotationEffect(
                        Angle(
                            degrees:
                                animate ?
                                360 : 0))
            }
        )
        .onAppear {
            animate
                .toggle()
        }
    }
}


来源:https://stackoverflow.com/questions/64165008/lazyvstack-scrolling-stops-animations

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!