Repeating animation on SwiftUI Image
Here is possible solution for continuous progressing on appear & start/stop. Tested with Xcode 11.4 / iOS 13.4.
struct PeopleList : View {
@State private var isAnimating = false
@State private var showProgress = false
var foreverAnimation: Animation {
Animation.linear(duration: 2.0)
.repeatForever(autoreverses: false)
}
var body: some View {
Button(action: { self.showProgress.toggle() }, label: {
if showProgress {
Image(systemName: "arrow.2.circlepath")
.rotationEffect(Angle(degrees: self.isAnimating ? 360 : 0.0))
.animation(self.isAnimating ? foreverAnimation : .default)
.onAppear { self.isAnimating = true }
.onDisappear { self.isAnimating = false }
} else {
Image(systemName: "arrow.2.circlepath")
}
})
.onAppear { self.showProgress = true }
}
}
SwiftUI animation: How to stagger repeating animation with delay
I think you can implement it using Timer and DispatchQueue, try this and see it's working as you want or no
struct Arrows: View {
private let arrowCount = 3
let timer = Timer.publish(every: 2, on: .main, in: .common).autoconnect()
@State var scale:CGFloat = 1.0
@State var fade:Double = 0.5
var body: some View {
ZStack {
Color(red: 29.0/255.0, green: 161.0/255.0, blue: 224.0/255.0).edgesIgnoringSafeArea(.all)
HStack{
ForEach(0..<self.arrowCount) { i in
ArrowShape()
.stroke(style: StrokeStyle(lineWidth: CGFloat(10),
lineCap: .round,
lineJoin: .round ))
.foregroundColor(Color.white)
.aspectRatio(CGSize(width: 28, height: 70), contentMode: .fit)
.frame(maxWidth: 20)
.animation(nil)
.opacity(self.fade)
.scaleEffect(self.scale)
.animation(
Animation.easeOut(duration: 0.5)
//.repeatForever(autoreverses: true)
.repeatCount(1, autoreverses: true)
.delay(0.2 * Double(i))
)
}.onReceive(self.timer) { _ in
self.scale = self.scale > 1 ? 1 : 1.2
self.fade = self.fade > 0.5 ? 0.5 : 1.0
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.scale = 1
self.fade = 0.5
}
}
}
}
}
}
Repeating SwiftUI animation gets choppy over time
Update: Xcode 13.4 / iOS 15.5
As on now it seems drawingGroup
does not have such positive effect as was before, because with used .animation(.., value:)
animation works properly and with low resource consumption.
Test module on GitHub
Original
Here is a solution - activating Metal by using .drawingGroup
and using explicit animation.
Works fine with Xcode 11.4 / iOS 13.4 - tested during 5 mins, CPU load 4-5%
ZStack {
// .. circles here
}.frame(maxWidth: .infinity, maxHeight: .infinity)
.drawingGroup()
.onAppear() {
withAnimation(Animation.linear(duration: 30).repeatForever(autoreverses: false)) {
self.animationPercent = 1
}
}
Note: findings - it looks like implicit animation recreates update stack in this case again and again, so they multiplied, but explicit animation activated only once.
Repeating Action Continuously In SwiftUI
Animation.basic is deprecated. Basic animations are now named after their curve types: like linear, etc:
var foreverAnimation: Animation {
Animation.linear(duration: 0.3)
.repeatForever()
}
Source:
https://forums.swift.org/t/swiftui-animation-basic-duration-curve-deprecated/27076
Delay a repeating animation in SwiftUI with between full autoreverse repeat cycles
A possible solution is to chain single pieces of animation using DispatchQueue.main.asyncAfter
. This gives you control when to delay specific parts.
Here is a demo:
struct SimpleBeatingView: View {
@State private var isBeating = false
@State private var heartState: HeartState = .normal
@State private var beatLength: TimeInterval = 1
@State private var beatDelay: TimeInterval = 3
var body: some View {
VStack {
Image(systemName: "heart.fill")
.imageScale(.large)
.font(.largeTitle)
.foregroundColor(.red)
.scaleEffect(heartState.scale)
Button("isBeating: \(String(isBeating))") {
isBeating.toggle()
}
HStack {
Text("beatLength")
Slider(value: $beatLength, in: 0.25...2)
}
HStack {
Text("beatDelay")
Slider(value: $beatDelay, in: 0...5)
}
}
.onChange(of: isBeating) { isBeating in
if isBeating {
startAnimation()
} else {
stopAnimation()
}
}
}
}
private extension SimpleBeatingView {
func startAnimation() {
isBeating = true
withAnimation(Animation.linear(duration: beatLength * 0.25)) {
heartState = .large
}
DispatchQueue.main.asyncAfter(deadline: .now() + beatLength * 0.25) {
withAnimation(Animation.linear(duration: beatLength * 0.5)) {
heartState = .small
}
}
DispatchQueue.main.asyncAfter(deadline: .now() + beatLength * 0.75) {
withAnimation(Animation.linear(duration: beatLength * 0.25)) {
heartState = .normal
}
}
DispatchQueue.main.asyncAfter(deadline: .now() + beatLength + beatDelay) {
withAnimation {
if isBeating {
startAnimation()
}
}
}
}
func stopAnimation() {
isBeating = false
}
}
enum HeartState {
case small, normal, large
var scale: CGFloat {
switch self {
case .small: return 0.5
case .normal: return 0.75
case .large: return 1
}
}
}
How to combine rotation and fade-out animation in SwiftUI
You need transition, because view (image in this case) is removed from view hierarchy. And transition is animated by container of removing view.
Note: it is better to link every animation to own switching state to avoid affect on other animations
Here is solution. Tested with Xcode 12.1 / iOS 14.1
struct Indicator: View {
@Binding var shown: Bool
@State private var rotating = false
@ViewBuilder
var body: some View {
VStack {
if shown {
Image("Ring")
.rotationEffect(Angle(degrees: rotating ? 360 : 0))
.animation(Animation.linear(duration: 1).repeatForever(autoreverses: false), value: rotating)
.transition(.opacity)
.onAppear {
self.rotating = true
}
}
}.animation(.default, value: shown)
}
}
Related Topics
Swiftui Present Alert with Input Field
Swift Performseguewithidentifier Shows Black Screen
Why Swift Throws Error When Using Optional Param in Closure Func
Incorrect String to Date Conversion Swift 3.0
Perform Segue from Another Class with Helper Function
Swift 3 - Uibutton Adding Settitle from Plist and Database
Get Bogus Value When Execute Break Point in a Variable
How to Make a Button Have a Rounded Border in Swift
Converting Url to String and Back Again
Default Optional Parameter in Swift Function
What Is the Swift Equivalent of -[Nsobject Description]
Swift, How to Implement Hashable Protocol Based on Object Reference
Singleton and Init with Parameter
How to Go from Cmutablepointer<Cgfloat> to Cgfloat[] in Swift
Fill Circle with Wave Animation in Swiftui