简体   繁体   中英

SwiftUI - how to cancel the default list animation

Is there a way to remove the default list row collapse animation without using .animation(nill) modifier on the list itself?

as you can see in the clip below, I've implemented an animation modifier on the list, but the default list collapse animation kinda disrupts the desired animation.

https://gfycat.com/cheerywelloffalleycat

I've updated the code below so you could run it on your Xcode without any dependencies.

  import SwiftUI

struct CurrencyComparison: View {
    @State var mainArray = ["10", "10","10", "10", "10", "10", "10", "10", "10", "10"]
    @State var array = ["10", "10","10", "10", "10", "10", "10", "10", "10", "10"]
    @State var secondArray = ["20", "20","20", "20", "20", "20", "20", "20", "20", "20"]
    @State var hide = false
    @State var direction = false
    @State var triggerAnimation: Bool


    var body: some View {
        VStack {


                List (self.mainArray, id:\.self) { item in

                    Text(item)
                        .foregroundColor(Color.black)
                        .frame(width: 40, height: 80)
                        .padding(.leading, 80)
                        .isHidden(self.hide)
                    Spacer()
                    Text(item)
                        .foregroundColor(Color.black)
                        .frame(width: 40, height: 40)
                        .padding(.trailing, 80)
                        .isHidden(self.hide)
                }
                .background(LinearGradient(gradient: Gradient(colors: [Color.blue, Color.red]), startPoint: .center, endPoint: .center))
                .animation(Animation.spring().delay(triggerAnimation ? 0 : 0.4))
                .transition(.asymmetric(insertion: AnyTransition.opacity.combined(with: .move(edge: .trailing)), removal: .move(edge: .trailing)))
                .cornerRadius(30)
                .padding(.top, 30)
                .padding(.bottom, 30)
                .shadow(radius: 10)
                .gesture(
                    DragGesture(minimumDistance: 50)

                        .onEnded { value in
                            self.hide.toggle()

                            DispatchQueue.main.asyncAfter(deadline: .now() ) {
                                if self.mainArray == self.array {
                                    self.mainArray = self.secondArray
                                } else {
                                    self.mainArray = self.array
                                }
                            }
                            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                                self.hide.toggle()
                            }
                    }
                )
        }
        .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height + 50, alignment: .top)
        .background(Color.gray.aspectRatio(contentMode: .fill))
        .padding(.top, 120)
    }
}

struct CurrencyComparison_Previews: PreviewProvider {
    @State static var staticBool = true
    static var previews: some View {
        CurrencyComparison(triggerAnimation: true)
    }
}


extension View {
    func isHidden(_ bool: Bool) -> some View {
        modifier(HiddenModifier(isHidden: bool))
    }
}

private struct HiddenModifier: ViewModifier {

    fileprivate let isHidden: Bool

    fileprivate func body(content: Content) -> some View {
        Group {
            if isHidden {
                content.hidden()

            } else {
                content
                    .transition(.asymmetric(insertion: AnyTransition.opacity.combined(with: .slide), removal: .move(edge: .trailing)))

            }
        }
    }
}

Okay so I've managed to find a solution that works. By changing the opacity of the list items when the list data source change happens.

Setting it to 0 when the undesired default animation play, and bringing it back to 1 when my the desired animations start playing.

That way I can hide the default list animation without removing my own desired animations :)

import SwiftUI

struct CurrencyComparison: View {
    @State var mainArray = ["10", "10","10", "10", "10", "10", "10", "10", "10", "10"]
    @State var array = ["10", "10","10", "10", "10", "10", "10", "10", "10", "10"]
    @State var secondArray = ["20", "20","20", "20", "20", "20", "20", "20", "20", "20"]
    @State var toggleHide = false
    @State var direction = false
    @State var triggerAnimation: Bool


    var body: some View {
        VStack {
            List (self.mainArray, id:\.self) { item in

                Text(item)
                    .foregroundColor(Color.black)
                    .frame(width: 40, height: 80)
                    .padding(.leading, 80)
                    .isHidden(self.toggleHide)
                    .opacity(self.toggleHide ? 0 : 1)
                Spacer()
                Text(item)
                    .foregroundColor(Color.black)
                    .frame(width: 40, height: 40)
                    .padding(.trailing, 80)
                    .isHidden(self.toggleHide)
                    .opacity(self.toggleHide ? 0 : 1)
            }
            .background(LinearGradient(gradient: Gradient(colors: [Color.blue, Color.red]), startPoint: .center, endPoint: .center))
            .animation(Animation.spring().delay(triggerAnimation ? 0 : 0.4))
            .transition(.asymmetric(insertion: AnyTransition.opacity.combined(with: .move(edge: .trailing)), removal: .move(edge: .trailing)))
            .cornerRadius(30)
            .padding(.top, 30)
            .padding(.bottom, 30)
            .shadow(radius: 10)
            .gesture(
                DragGesture(minimumDistance: 50)

                    .onEnded { value in
                        self.toggleHide.toggle()

                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
                            if self.mainArray == self.array {
                                self.mainArray = self.secondArray
                            } else {
                                self.mainArray = self.array
                            }
                        }

                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.9) {
                            self.toggleHide.toggle()
                        }
                }
            )
        }
        .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height + 50, alignment: .top)
        .background(Color.gray.aspectRatio(contentMode: .fill))
        .padding(.top, 120)
    }
}

struct CurrencyComparison_Previews: PreviewProvider {
    @State static var staticBool = true
    static var previews: some View {
        CurrencyComparison(triggerAnimation: true)
    }
}


extension View {
    func isHidden(_ bool: Bool) -> some View {
        modifier(HiddenModifier(isHidden: bool))
    }
}

private struct HiddenModifier: ViewModifier {

    fileprivate let isHidden: Bool

    fileprivate func body(content: Content) -> some View {
        Group {
            if isHidden {
                content.hidden()

            } else {
                content
                    .transition(.asymmetric(insertion: AnyTransition.opacity.combined(with: .slide), removal: .move(edge: .trailing)))

            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM