Animation
Skip support for SwiftUI.Animation ↗.
The following example screens and source code is from SkipUI’s
Showcase sample app
AnimationPlayground.swift ↗
import SwiftUI
struct AnimationPlayground: View { @State var isOn = false @State var unrelatedIsOn = false @State var isRepeatOn = false
var body: some View { ScrollView { VStack(spacing: 16) { HStack { Text(".opacity") Spacer() Color.red .frame(width: 100, height: 100) .opacity(isOn ? 0.2 : 1.0) .onTapGesture { isOn = !isOn } } HStack { Text(".opacity.animation") Spacer() Color.red .frame(width: 100, height: 100) .opacity(isOn ? 0.2 : 1.0) .animation(.default, value: isOn) .onTapGesture { isOn = !isOn } } HStack { Text(".opacity.animation\n(different value)") Spacer() Color.red .frame(width: 100, height: 100) .opacity(isOn || unrelatedIsOn ? 0.2 : 1.0) .animation(.default, value: isOn) .onTapGesture { unrelatedIsOn = !unrelatedIsOn } } Button("withAnimation") { withAnimation { isOn = !isOn } } .buttonStyle(.bordered) HStack { Text(".foreground/.background") Spacer() Text("Text") .font(.largeTitle) .bold() .frame(width: 100, height: 100) .foregroundStyle(isOn ? Color.white : Color.black) .background(isOn ? Color.black : Color.white) .border(Color.blue) .onTapGesture { isOn = !isOn } } HStack { Text(".foreground/.background.animation") Spacer() Text("Text") .font(.largeTitle) .bold() .frame(width: 100, height: 100) .foregroundStyle(isOn ? Color.white : Color.black) .background(isOn ? Color.black : Color.white) .border(Color.blue) .animation(.default, value: isOn) .onTapGesture { isOn = !isOn } } Button("withAnimation") { withAnimation { isOn = !isOn } } .buttonStyle(.bordered) HStack { Text(".fill") Spacer() Circle() .fill(isOn ? Color.blue : Color.red) .frame(width: 100, height: 100) .onTapGesture { isOn = !isOn } } HStack { Text(".fill.animation") Spacer() Circle() .fill(isOn ? Color.blue : Color.red) .frame(width: 100, height: 100) .animation(.default, value: isOn) .onTapGesture { isOn = !isOn } } Button("withAnimation") { withAnimation { isOn = !isOn } } .buttonStyle(.bordered) HStack { Text(".offset") Spacer() ZStack { Color.red .frame(width: 20, height: 20) .offset(isOn ? CGSize(width: 50, height: 10) : CGSize(width: 0, height: 0)) } .frame(width: 100, height: 100) .background(.gray) .onTapGesture { isOn = !isOn } } HStack { Text(".offset.animation") Spacer() ZStack { Color.red .frame(width: 20, height: 20) .offset(isOn ? CGSize(width: 50, height: 10) : CGSize(width: 0, height: 0)) .animation(.default, value: isOn) } .frame(width: 100, height: 100) .background(.gray) .onTapGesture { isOn = !isOn } } Button("withAnimation") { withAnimation { isOn = !isOn } } .buttonStyle(.bordered) HStack { Text(".frame") Spacer() ZStack { Color.red .frame(width: isOn ? 100.0 : 40.0, height: isOn ? 60.0 : 40.0) } .frame(width: 100, height: 100) .background(.gray) .onTapGesture { isOn = !isOn } } HStack { Text(".frame.animation") Spacer() ZStack { Color.red .frame(width: isOn ? 100.0 : 40.0, height: isOn ? 60.0 : 40.0) .animation(.default, value: isOn) } .frame(width: 100, height: 100) .background(.gray) .onTapGesture { isOn = !isOn } } Button("withAnimation") { withAnimation { isOn = !isOn } } .buttonStyle(.bordered) HStack { Text(".rotationEffect") Spacer() Color.red .frame(width: 100, height: 100) .rotationEffect(isOn ? .degrees(45) : .degrees(0)) .onTapGesture { isOn = !isOn } } HStack { Text(".rotationEffect.animation") Spacer() Color.red .frame(width: 100, height: 100) .rotationEffect(isOn ? .degrees(45) : .degrees(0)) .animation(.default, value: isOn) .onTapGesture { isOn = !isOn } } Button("withAnimation") { withAnimation { isOn = !isOn } } .buttonStyle(.bordered) HStack { Text(".scaleEffect") Spacer() Color.red .frame(width: 100, height: 100) .scaleEffect(isOn ? 0.5 : 1.0) .onTapGesture { isOn = !isOn } } HStack { Text(".scaleEffect.animation") Spacer() Color.red .frame(width: 100, height: 100) .scaleEffect(isOn ? 0.5 : 1.0) .animation(.default, value: isOn) .onTapGesture { isOn = !isOn } } Button("withAnimation") { withAnimation { isOn = !isOn } } .buttonStyle(.bordered) HStack { Text(".font") Spacer() Text("Hello") .font(.system(size: isOn ? 30.0 : 20.0)) .frame(width: 100, height: 100) .border(Color.blue) .onTapGesture { isOn = !isOn } } HStack { Text(".font.animation") Spacer() Text("Hello") .font(.system(size: isOn ? 30.0 : 20.0)) .frame(width: 100, height: 100) .border(Color.blue) .animation(.default, value: isOn) .onTapGesture { isOn = !isOn } } Button("withAnimation") { withAnimation { isOn = !isOn } } .buttonStyle(.bordered) HStack { Text(".animation(.spring)") Spacer() ZStack { Color.red .frame(width: 20, height: 20) .offset(isOn ? CGSize(width: 0, height: 50) : CGSize(width: 0, height: -50)) .animation(.spring, value: isOn) } .frame(width: 100, height: 100) .background(.gray) .onTapGesture { isOn = !isOn } } HStack { Text("withAnimation(.spring)") Spacer() ZStack { Color.red .frame(width: 20, height: 20) .offset(isOn ? CGSize(width: 0, height: 50) : CGSize(width: 0, height: -50)) } .frame(width: 100, height: 100) .background(.gray) .onTapGesture { withAnimation(.spring) { isOn = !isOn } } } HStack { Text(".animation(.easeIn(duration: 1))") Spacer() ZStack { Color.red .frame(width: 20, height: 20) .offset(isOn ? CGSize(width: 0, height: 50) : CGSize(width: 0, height: -50)) .animation(.easeIn(duration: 1), value: isOn) } .frame(width: 100, height: 100) .background(.gray) .onTapGesture { isOn = !isOn } } HStack { Text("withAnimation(.easeIn(duration: 1))") Spacer() ZStack { Color.red .frame(width: 20, height: 20) .offset(isOn ? CGSize(width: 0, height: 50) : CGSize(width: 0, height: -50)) } .frame(width: 100, height: 100) .background(.gray) .onTapGesture { withAnimation(.easeIn(duration: 1)) { isOn = !isOn } } } HStack { Text(".animation(repeatCount(3))") Spacer() ZStack { Color.red .frame(width: 20, height: 20) .offset(isOn ? CGSize(width: 0, height: 50) : CGSize(width: 0, height: -50)) .animation(.default.repeatCount(3), value: isOn) } .frame(width: 100, height: 100) .background(.gray) .onTapGesture { isOn = !isOn } } HStack { Text("withAnimation(repeatCount(3))") Spacer() ZStack { Color.red .frame(width: 20, height: 20) .offset(isOn ? CGSize(width: 0, height: 50) : CGSize(width: 0, height: -50)) } .frame(width: 100, height: 100) .background(.gray) .onTapGesture { withAnimation(.default.repeatCount(3)) { isOn = !isOn } } } HStack { Text(".animation(autoreverses: false))") Spacer() ZStack { Color.red .frame(width: 20, height: 20) .offset(isOn ? CGSize(width: 0, height: 50) : CGSize(width: 0, height: -50)) .animation(.default.repeatCount(3, autoreverses: false), value: isOn) } .frame(width: 100, height: 100) .background(.gray) .onTapGesture { isOn = !isOn } } HStack { Text(".repeatForever()") Spacer() ZStack { Color.red .frame(width: 20, height: 20) .offset(isRepeatOn ? CGSize(width: 0, height: 50) : CGSize(width: 0, height: -50)) .animation(.default.repeatForever(), value: isRepeatOn) } .frame(width: 100, height: 100) .background(.gray) .onAppear { isRepeatOn = true } .onTapGesture { isOn = !isOn } } NavigationLink("Push") { Text("Pushed") } .buttonStyle(.bordered) } .padding() } .toolbar { PlaygroundSourceLink(file: "AnimationPlayground.swift") } }}