简体   繁体   中英

How to make a reusable modifier for view lifecycle events (onAppear, onDisappear)?

I have a common fadeIn and fadeOut animation that I use for when views appear and disappear:

struct ActiveView: View {
    @State var showCode: Bool = false
    @State var opacity = 0.0
    var body: some View {

    if self.showCode {
        Color.black.opacity(0.7)
            .onAppear{
                let animation = Animation.easeIn(duration: 0.5)
                    return withAnimation(animation) {
                        self.opacity = 1
                    }
            }
            .onDisappear{
                let animation = Animation.easeOut(duration: 0.5)
                    return withAnimation(animation) {
                        self.opacity = 0
                    }
            }
    }
    }
}

However, I want to use these same animations on other views, so I want it to be simple and reusable, like this:

if self.showCode {
    Color.black.opacity(0.7)
        .fadeAnimation()
}

How can I achieve this?

EDIT:

Trying to implement a View extension:

extension View {
    func fadeAnimation(opacity: Binding<Double>) -> some View {
        self.onAppear{
            let animation = Animation.easeIn(duration: 0.5)
                return withAnimation(animation) {
                    opacity = 1
                }
        }
        .onDisappear{
            let animation = Animation.easeOut(duration: 0.5)
                return withAnimation(animation) {
                    opacity = 0
                }
        }
    }
}

What you try to do is already present and named opacity transition , which is written in one modifier.

Here is a demo:

演示

struct ActiveView: View {
    @State var showCode: Bool = false
    var body: some View {
        ZStack {
            if self.showCode {
                Color.black.opacity(0.7)
                    .transition(AnyTransition.opacity.animation(.default))
            }
            Button("Demo") { self.showCode.toggle() }
        }.frame(maxWidth: .infinity, maxHeight: .infinity)
    }
}

The functionality that you are trying to implement is already part of the Animation and Transition modifiers from SwiftUI.

Therefore, you can add .transition modifier to any of your Views and it will animate its insertion and removal.

if self.showCode {
    Color.black.opacity(0.7)
        .transition(AnyTransition.opacity.animation(.easeInOut(duration: 0.5)))
}

You can use a multitude of different transitions like .slide , .scale , .offset , etc. More information about transitionshere .

You can even create custom transitions with different actions for insertion and removal. In your case, different animation curves.

extension AnyTransition {
    static var fadeTransition: AnyTransition {
        .asymmetric(
            insertion: AnyTransition.opacity.animation(.easeIn(duration: 0.5)),
            removal: AnyTransition.opacity.animation(.easeOut(duration: 0.5))
        )
    }
}

And use it like this:

if self.showCode {
    Color.black.opacity(0.7)
        .transition(.fadeTransition)
}

Hope this helps !

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