\n
Curious what exactly is causing the behavior
\nstruct LandingPage: View {\n @AppStorage("signedIn") var signedIn = false\n @Environment (\\.dismiss) var dismiss\n \n @StateObject var vm = DashboardLogic()\n \n @State private var animateGradient = false\n\n \n @ViewBuilder\n var body: some View {\n if(signedIn){\n // Text("Random Page")\n }\n else{\n NavigationView{\n VStack{\n Image("bodybuilding-1") // << main image\n .resizable()\n .scaledToFit()\n .frame(width:150, height:150)\n //.renderingMode(.template)\n .foregroundColor(.black)\n .padding(.top, 200)\n \n Text("Welcome to Meal Journal")\n .font(.title)\n .padding()\n \n .offset(y:-25) // << adjusts title\n \n VStack{\n NavigationLink(destination:dummyPage() .navigationBarHidden(true),\n label:{\n Text("Get Started").fontWeight(.bold)\n .frame(minWidth: 0, maxWidth: 200)\n .padding(10)\n .foregroundColor(.white)\n //draw rectange around buttons\n .background(\n RoundedRectangle(cornerRadius: 20)\n .fill(\n LinearGradient(\n colors: [.orange, .yellow],\n startPoint: .topLeading,\n endPoint: .bottomTrailing\n )))\n })\n \n NavigationLink(destination: DummyPage().navigationBarHidden(true), label: {\n Text("Login").fontWeight(.semibold)\n .frame(minWidth:0, maxWidth: 200)\n .padding(10)\n .foregroundColor(.black)\n .overlay( RoundedRectangle(cornerRadius: 25)\n .stroke(Color.gray, lineWidth: 3)\n )\n })\n .padding()\n }\n Rectangle()\n .frame(height: 0)\n .frame(maxWidth: .infinity, maxHeight: .infinity)\n .ignoresSafeArea()\n }\n //.background(Color.purple)\n .background(RadialGradient(gradient: Gradient(colors: [.yellow, .green]), center: .center, startRadius: 312, endRadius: animateGradient ? 100 : 450))\n .onAppear {\n DispatchQueue.main.async { \n withAnimation(.linear(duration: 2.0).repeatForever(autoreverses: true)) {\n animateGradient.toggle()\n }\n }\n }\n \n }\n \n }\n }\n}\n
\n","author":{"@type":"Person","name":"Swink"},"upvoteCount":1,"answerCount":2,"acceptedAnswer":{"@type":"Answer","text":"I didn't carefully check your entire code, but one thing that may help is remembering that background is a View on its own, so you can (and often have to) apply modifiers to the background view itself. So instead of .onAppear
on the parent view, add it to a background view, i.e.:
var backgroundView: some View {\n \n RadialGradient(gradient: Gradient(colors: [.yellow, .green]), center: .center, startRadius: 312, endRadius: animateGradient ? 100 : 450)\n .onAppear {\n withAnimation(.linear(duration: 2.0).repeatForever(autoreverses: true)) {\n animateGradient.toggle()\n }\n }\n }\n}\n
\nand then parent view simply uses background view:
\nVStack {\n Image("bodybuilding-1")\n ...\n}\n.background(backgroundView)\n
\nPlayground example:
\nstruct AnimatedBackgroundView: View {\n \n @State private var animateGradient = false\n \n @State var scale = 1.0\n\n var body: some View {\n \n VStack {\n Text("Hello")\n Button("Do it", action: {})\n }\n .frame(\n maxWidth: .infinity,\n maxHeight: .infinity\n )\n .scaleEffect(scale)\n .background(backgroundView)\n }\n \n var backgroundView: some View {\n \n RadialGradient(gradient: Gradient(colors: [.yellow, .green]), center: .center, startRadius: 312, endRadius: animateGradient ? 100 : 450)\n .onAppear {\n withAnimation(.linear(duration: 2.0).repeatForever(autoreverses: true)) {\n animateGradient.toggle()\n }\n }\n }\n}\n\nstruct ContentView: View {\n\n var body: some View {\n \n AnimatedBackgroundView()\n .frame(\n width: 500,\n height: 600\n )\n }\n}\n \nPlaygroundPage.current.setLiveView(ContentView())\n
\nBut like I said: I didn't investigate your entire code, so maybe some other issues prevent it from working
\n","author":{"@type":"Person","name":"timbre timbre"},"upvoteCount":3}}}Reputation: 457
Attempting to fool around with animating a background gradient. When animation is toggled, it would change the end radius. It is creating weird behavior whenever I incorporate the animation (gif below) where it moves the whole VStack.
I tried to put the stack in a ZStack thinking that would be a solution, but end result still the same.
Curious what exactly is causing the behavior
struct LandingPage: View {
@AppStorage("signedIn") var signedIn = false
@Environment (\.dismiss) var dismiss
@StateObject var vm = DashboardLogic()
@State private var animateGradient = false
@ViewBuilder
var body: some View {
if(signedIn){
// Text("Random Page")
}
else{
NavigationView{
VStack{
Image("bodybuilding-1") // << main image
.resizable()
.scaledToFit()
.frame(width:150, height:150)
//.renderingMode(.template)
.foregroundColor(.black)
.padding(.top, 200)
Text("Welcome to Meal Journal")
.font(.title)
.padding()
.offset(y:-25) // << adjusts title
VStack{
NavigationLink(destination:dummyPage() .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: DummyPage().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))
.onAppear {
DispatchQueue.main.async {
withAnimation(.linear(duration: 2.0).repeatForever(autoreverses: true)) {
animateGradient.toggle()
}
}
}
}
}
}
}
Upvotes: 1
Views: 324
Reputation: 23
You should animate into task {} insterad of onAppear. With this animation will work as well instead of whole view. We have call this asynchronously
@State var animateGradient = false
LinearGradient(colors: [.purple, .yellow], startPoint: animateGradient ? .topTrailing : .bottomTrailing, endPoint: animateGradient ? .bottomLeading : .topTrailing)
.ignoresSafeArea()
.frame(width: 200, height: 200)
.task {
withAnimation(.linear(duration: 5.0).repeatForever(autoreverses: true)) {
animateGradient.toggle()
}
}
Upvotes: 1
Reputation: 14004
I didn't carefully check your entire code, but one thing that may help is remembering that background is a View on its own, so you can (and often have to) apply modifiers to the background view itself. So instead of .onAppear
on the parent view, add it to a background view, i.e.:
var backgroundView: some View {
RadialGradient(gradient: Gradient(colors: [.yellow, .green]), center: .center, startRadius: 312, endRadius: animateGradient ? 100 : 450)
.onAppear {
withAnimation(.linear(duration: 2.0).repeatForever(autoreverses: true)) {
animateGradient.toggle()
}
}
}
}
and then parent view simply uses background view:
VStack {
Image("bodybuilding-1")
...
}
.background(backgroundView)
Playground example:
struct AnimatedBackgroundView: View {
@State private var animateGradient = false
@State var scale = 1.0
var body: some View {
VStack {
Text("Hello")
Button("Do it", action: {})
}
.frame(
maxWidth: .infinity,
maxHeight: .infinity
)
.scaleEffect(scale)
.background(backgroundView)
}
var backgroundView: some View {
RadialGradient(gradient: Gradient(colors: [.yellow, .green]), center: .center, startRadius: 312, endRadius: animateGradient ? 100 : 450)
.onAppear {
withAnimation(.linear(duration: 2.0).repeatForever(autoreverses: true)) {
animateGradient.toggle()
}
}
}
}
struct ContentView: View {
var body: some View {
AnimatedBackgroundView()
.frame(
width: 500,
height: 600
)
}
}
PlaygroundPage.current.setLiveView(ContentView())
But like I said: I didn't investigate your entire code, so maybe some other issues prevent it from working
Upvotes: 3