How to delay animation in SwiftUI?
From the partial code you provided it seems you are manipulating the same variables in both closures. Change that to individual ones for each field.
Reason:
when you do:
@State private var changeVar = 0.0
withAnimation(...){
changeVar = 1.0
}
SwiftUI will change that value incrementally from the value it is at the moment the animation starts to the value provided in the closure. As soon as the value changes the view gets redrawn with the current value of changeVar
. As you use the same var for both Views the changes are applied to both at the same time. Hence the animation starts for both at the same time.
How to create animation with delay when dismiss view swiftui
This would be one way to do it. Without the NavigationLink
you have full control over all animations and transitions.
struct DetailView: View {
@Binding var showDetail:Bool
var body: some View {
Button(
"Here is Detail View. Tap to go back.",
action: {
withAnimation(Animation.linear.delay(2)){
self.showDetail = false
}
}
).frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity).background(Color.yellow)
}
}
struct RootView: View {
@State var showDetail = false
var body: some View {
VStack {
if showDetail{
DetailView(showDetail:self.$showDetail).transition(.move(edge: .trailing))
}else{
Button("I am Root. Tap for Detail View."){
withAnimation(.linear){
self.showDetail = true
}
}
}
}.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity).background(Color.red)
}
}
How to trigger action after x seconds in swiftUI
Create a delay, which then sets the @State
property hasTimeElapsed
to true
when the time has elapsed, updating the view body.
With Swift 5.5 and the new concurrency updates (async
& await
), you can now use task(_:)
like the following:
struct ContentView: View {
@State private var hasTimeElapsed = false
var body: some View {
Text(hasTimeElapsed ? "Sorry, too late." : "Please enter above.")
.task(delayText)
}
private func delayText() async {
// Delay of 7.5 seconds (1 second = 1_000_000_000 nanoseconds)
try? await Task.sleep(nanoseconds: 7_500_000_000)
hasTimeElapsed = true
}
}
See more info about Task.sleep(nanoseconds:)
in this answer.
Older versions
Xcode 13.0+ now supports concurrency, backwards compatible! However, here is still the 'old' way to do it:
You can use DispatchQueue
to delay something. Trigger it with onAppear(perform:)
(which happens when the view first appears). You could also hook the delay up to a Button instead if wanted.
Example:
struct ContentView: View {
@State private var hasTimeElapsed = false
var body: some View {
Text(hasTimeElapsed ? "Sorry, too late." : "Please enter above.")
.onAppear(perform: delayText)
}
private func delayText() {
// Delay of 7.5 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 7.5) {
hasTimeElapsed = true
}
}
}
Delay SwiftUI combined transitions
Try this
extension AnyTransition {
static var delayAndFade: AnyTransition {
return AnyTransition.identity
.combined(with: .opacity)
.animation(.default.delay(3))
}
}
If you want to move a view, you should animate its offset
using the withAnimation
function.
Text("Move and fade.")
.offset(y: offset)
.transition(.delayAndFade)
struct ContentView: View {
@State private var showDetails = false
@State var offset:CGFloat = 0
var body: some View {
VStack {
Button("Press to show details") {
showDetails.toggle()
withAnimation(.default.delay(3)) {
self.offset = -20
}
}
if showDetails {
Text("Move and fade.")
.offset(y: offset)
.transition(.delayAndFade)
}
}
}
}
Update
extension AnyTransition {
static var moveAndFade: AnyTransition {
return AnyTransition.move(edge: .top)
.combined(with: .opacity)
}
}
Try this
HStack {
Text("Move and fade.")
}
.animation(Animation.default.delay(2))
.transition(.moveAndFade)
It works with all kind of views except Text.
struct ContentView: View {
@State private var showDetails = false
@State var offset:CGFloat = 0
var body: some View {
VStack {
Button("Press to show details") {
showDetails.toggle()
}
if showDetails {
// Works!
HStack {
Text("Move and fade.")
}
.animation(Animation.default.delay(2))
.transition(.moveAndFade)
Button("Move and fade.") {}
.animation(Animation.default.delay(2))
.transition(.moveAndFade)
// Does not work
Text("Move and fade.")
.animation(Animation.default.delay(2))
.transition(.moveAndFade)
}
}
}
}
Delay a transition in SwiftUI
If you add an explicit id
it works as you would like. Note, I made only one animation delay to make it a little more obvious that this is working.
struct ContentView: View {
@State var showOne = true
var body:some View {
VStack {
if showOne {
HStack {
Spacer()
Text("One")
Spacer()
}
.background(Color.red)
.id("one")
.animation(Animation.default)
.transition(.slide)
} else {
HStack {
Spacer()
Text("Two")
Spacer()
}
.background(Color.blue)
.id("two")
.animation(Animation.default.delay(2))
.transition(.slide)
}
Button("Toggle") {
withAnimation {
self.showOne.toggle()
}
}
}
}
}
I've found an explicit id
to be helpful most of the time I want to use a transition. In your example, not using the id
can cause the text to change before the background. This would seem to be a bug, and I recommend filing feedback on it.
SwiftUI synchronizing multiple SwiftUI animations with delays
The fix for the out of sync views is to put them all in one view and that view syncs everything simultaneously. It took me some time to work out the pattern, but here it is:
struct MyRepeatingItemView: View {
@State var isTranslated = false
var body: some View {
ZStack {
Rectangle()
.fill(Color.red)
.frame(width: 256, height: 256)
.opacity(isTranslated ? 0 : 0.25)
.scaleEffect(isTranslated ? 1 : 0.75)
Rectangle()
.fill(Color.red)
.frame(width: 256, height: 256)
.opacity(0.25)
.scaleEffect(isTranslated ? 0.75 : 0.5)
Rectangle()
.fill(Color.red)
.frame(width: 256, height: 256)
.opacity(0.25)
.scaleEffect(isTranslated ? 0.5 : 0.25)
Rectangle()
.fill(Color.red)
.frame(width: 256, height: 256)
.opacity(0.25)
.scaleEffect(isTranslated ? 0.25 : 0)
}
.onAppear {
withAnimation(Animation.linear(duration: 1).repeatForever(autoreverses: false)) {
isTranslated.toggle()
}
}
}
}
struct MyRepeatingContainerView: View {
var body: some View {
ZStack {
Color.blue
.frame(width: 256, height: 2)
Color.blue
.frame(width: 2, height: 256)
MyRepeatingItemView()
}
}
}
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
}
}
}
}
}
}
Related Topics
Compiler Segmentation Fault While Using Set in Swift
Swift: Trunc a Floating Number to Show It in a Label
Swiftui Go Back Programmatically from Representable to View
Why Is This Predicate Format Being Turned into '= Nil'
Cannot Use Mutating Member ... Because Append
Swift - Connect Delegate to Custom Xib Cell
Why Does a Function Have Long-Term Write Access to All of Its In-Out Parameters
Convert Input Data to Integer in Swift
Swift Bug? Calling Super Class Method When Subclass with Generic Type
List Scroll Freeze on Catalyst Navigationview
Swift Auto Completion Not Working in Xcode 6 Beta
Swift Janus Can Not Publish Video, But Get Remote Video Successful - Can Not Know Reason
Index or Range of Second Ocurence of Bytes in File
Cannot Convert Value of Type 'Foo!' to Expected Argument Type 'Foo!'
Modify Scpreferences Persistent Storage: Invalid Argument
How to Pass Text from Cell to Textview in Another View Controller