UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: Why isn't background animating

Forums > SwiftUI

@Swink  

Attempting to have a background with a gradient that animates. The background pops up, but the animation does not trigger. Very curious what is happening to cause the animation to not trigger. Thanks in advance for the help!

struct LandingPage: View {

    @State private var animateGradient = false

    @ViewBuilder
    var body: some View {
        if(signedIn){
           RandomView()
        }
        else{
            NavigationView{
                VStack{
                        Image("Image default") // << main image
                            .resizable()
                            .scaledToFit()
                            .frame(width:150, height:150)
                            //.renderingMode(.template)
                            .foregroundColor(.black)
                            .padding(.top, 200)

                        Text("Welcome to Landing Page")
                            .font(.title)
                            .padding()

                    .offset(y:-25) // << adjusts title

                    VStack{
                        NavigationLink(destination:createUserAccount() .navigationBarHidden(true),
                       label:{
                            Text("Get Started").fontWeight(.bold)
                                .frame(minWidth: 0, maxWidth: 200)
                                .padding(10)
                                .foregroundColor(.white)
                            //draw rectange around buttons
                                .background(
                                    RoundedRectangle(cornerRadius: 20)
                                        .fill(
                                            LinearGradient(
                                                colors: [.orange, .yellow],
                                                startPoint: .topLeading,
                                                endPoint: .bottomTrailing
                                            )))
                                        })

                        NavigationLink(destination: userLogin(signUpController: signUpController).navigationBarHidden(true), label: {
                            Text("Login").fontWeight(.semibold)
                                .frame(minWidth:0, maxWidth: 200)
                                .padding(10)
                                .foregroundColor(.black)
                                .overlay( RoundedRectangle(cornerRadius: 25)
                                            .stroke(Color.gray, lineWidth: 3)
                                    )
                        })
                            .padding()
                    }
                    Rectangle()
                        .frame(height: 0)
                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                        .ignoresSafeArea()
                }
                //.background(Color.purple)
                .background(RadialGradient(gradient: Gradient(colors: [.yellow, .green]), center: .center, startRadius: 312, endRadius: animateGradient ? 100 : 450))
                .animation(.linear(duration: 5).repeatForever(autoreverses: true),
                                               value: animateGradient)
                .onAppear {
                    DispatchQueue.main.async {
                            animateGradient.toggle()

                    }

                }
                 .frame(maxWidth: .infinity, maxHeight: .infinity)
                 .ignoresSafeArea()

            }

        }
    }
}

2      

@Swink gets animated about a view problem:

Very curious what is happening to cause the animation to not trigger.

Somewhere in these archives, I wrote a small piece about eating an elephant.

See -> Eating an Elephant

How does this relate to your troubles?

You might have too many bites on your plate. It's difficult to chew what you have with so much more in the way.

One Bite at a Time

Clear some things off your plate and think about animating just the background. That's what I did in the code below. I thought about a simple background that toggles from one color to another. The rectangle and globe are just distractions. Comment them out, or delete them. They don't help you solve the problem.

Then work through your design goals. First, you need the view to load itself and initialize all its properties.
Then you want to flip a switch in your application to start the animation.
Then you change the background to the new look with animation. You've told the animation to start with one color and morph into another color.
Then you let the animation know it should reverse itself. And repeat. Forever.

Paste this code into a new project and give it a test drive.

Next, Eat Another Piece

If this works, and you understand the sequence of events, you're ready for the next bite of elephant.
I'd try to change the plain colors to gradients. Maybe change just one at first.

Keep Coding!

Please return and let us know how you solved this!

// Paste into a new Xcode project.
struct BackgroundPulse: View {
    // Think of this as a light switch in your classroom.
    // Once the switch is turned on (changed?) what do you want to happen?
    // Also, take note! This only is changed ONCE in your app.
    // The animation is set to >repeatForever< so no need to turn this on and off!
    @State private var theColor = Color.clear

    // I like computed vars.
    // Keep the view logic nice and tidy.
    var nextBackgroundColor: Color {
        theColor == .indigo ? .green : .indigo  // toggle
    }

    var body: some View {
        ZStack {
            // This content is a distraction. Feel free to mark as comments
            // until you've got the background animations working. 
            // But you do need something to populate the ZStack. 🙂
            Rectangle()
                .fill(Color.pink.opacity(0.8))
                .frame(width: 150, height: 150)
                .cornerRadius(30)
            Image(systemName: "globe")
                .font(.system(size: 90, weight: .thin))
                .foregroundColor(.white)
        }
        // Think of this as turning on the light switch.
        // You're changing the state of your light bulb.
        .onAppear { theColor = .indigo } // kick off the fun!
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .ignoresSafeArea()
        .background(nextBackgroundColor) // Just declare what you want to see!
        // Set the animation rules.
        // 1. Set type and duration.
        // 2. Indicate it repeats forever, and reverses.
        // 3. Wire it up to a light switch. When the value changes, start the animation.
        .animation(.linear(duration: 3.0).repeatForever(autoreverses: true), value: theColor)
    }
}

2      

I don't really know enough about it to give you the reason why it isn't animating the way you have it.

But I did find a way to make it work by slightly modifying your code, and it seems to have something to do with using the .background() modifier.

Basically, I just removed the .background() modifier from your VStack (The one just above the .animation() modifier)

Then, I added the gradient as a background by wrapping your entire VStack in a ZStack, and putting the RadialGradient() initializer into the ZStack just before the VStack

Then, move all of the modifiers that were attached to the VStack to the ZStack instead.

Then the background animates.

(I also changed your NavigationLinks to point to Text("Hi") Views here, just so I could get the code to run easily on my end.)

@ViewBuilder var body: some View {
        if(signedIn) {
            Text("Hi")
        } else {
            NavigationView{
                ZStack {
                    RadialGradient(gradient: Gradient(colors: [.yellow, .green]), center: .center, startRadius: 312, endRadius: animateGradient ? 100 : 450)

                    VStack{
                        Image(systemName: "globe") // << main image
                            .resizable()
                            .scaledToFit()
                            .frame(width:150, height:150)
                            .foregroundColor(.black)
                            .padding(.top, 200)

                        Text("Welcome to Landing Page")
                            .font(.title)
                            .padding()
                            .offset(y:-25) // << adjusts title

                        NavigationLink(destination: Text("Hi") .navigationBarHidden(true), label:{
                            Text("Get Started").fontWeight(.bold)
                                .frame(minWidth: 0, maxWidth: 200)
                                .padding(10)
                                .foregroundColor(.white)
                                .background(RoundedRectangle(cornerRadius: 20).fill(
                                    LinearGradient(
                                        colors: [.orange, .yellow],
                                        startPoint: .topLeading,
                                        endPoint: .bottomTrailing
                                    )
                                ))
                        })

                        NavigationLink(destination: Text("hi").navigationBarHidden(true), label: {
                            Text("Login").fontWeight(.semibold)
                                .frame(minWidth:0, maxWidth: 200)
                                .padding(10)
                                .foregroundColor(.black)
                                .overlay( RoundedRectangle(cornerRadius: 25)
                                    .stroke(Color.gray, lineWidth: 3)
                                )
                        })
                        .padding()

                        Rectangle()
                            .frame(height: 0)
                            .frame(maxWidth: .infinity, maxHeight: .infinity)
                            .ignoresSafeArea()
                    }
                }
                .animation(.linear(duration: 5).repeatForever(autoreverses: true), value: animateGradient)
                .onAppear {
                    DispatchQueue.main.async {
                        animateGradient.toggle()
                    }
                }
                .frame(maxWidth: .infinity, maxHeight: .infinity)
                .ignoresSafeArea()
            }
        }
    }

2      

@Swink  

@Obelix Thank you, thank you, thank you for this. As someone who is self taught and doesn't have any mentors, you have been tremendous in the few questions you helped me on with taking the time, going over the approach in detail and just helping me out. Learned so much from your answers. I owe you a beer (if you don't drink a coke) if we ever cross paths. Thank you again for this

@Fly0strich Thank you for this approach. This helped me figure out what I was doing wrong without rearranging the code too much. I appreciate it !!

2      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.