The simple code below moves the text by updating the @State var offset
within a withAnimation
block.
struct ContentView: View {
@State var offset: CGFloat = 0
var body: some View {
NavigationView {
VStack {
Text("Some moving text")
.offset(y: offset)
Button("Change Offset") {
withAnimation(.easeInOut(duration: 1.0)) {
offset = .random(in: -400...400)
}
}
}
}
}
}
Is it somehow possible to access the animation properties like the current value/offset and speed while the animation is runnig?
For example I would like to add blur to the Text
depending on the current speed of the animation: The faster the animation the stronger the blur / grater the blur radius.
Is this possible?
2
Answers
Given the use case, the speed/velocity doesn’t really matter, as I don’t believe respecting it precisely would be noticeable, and developing a method to achieve the desired effect based on the observed or calculated speed may be overkill.
The (variable) speed is actually given by timing curve associated with the selected animation –
.easeInOut
. More importantly, though, is the animation duration. This duration is the same, regardless of the distance travelled by the object/text.If the duration is the same, it means any values changed/animated using the same animation and duration will:
With this in mind, if we know the text will take one second to move from its current offset to the new offset, any blur applied to it should:
The simplest way to achieve this is to animate the change in the blur value from zero to an appropriate value:
This can be easily done by setting the blur value with the same (or similar) animation but with half the duration value, and then animating again to reset the value on completion of the initial animation:
Here’s the full code with some comments that hopefully explains everything:
You can get the current value of an animation by conforming to
Animatable
. For example,Every frame, the setter of
animatableData
will be called with the current value of the offset, and thebody
will be called to re-evaluate how the view should look. Try putting someprint
s inbody
and animate theoffset
🙂If you do
onChange(of: offset)
then calculate the difference between the old and new value, you can get an approximation of the velocity. You’d also need a way to detect whether the animation ended, so that the velocity can be set back to 0.Example Usage:
If you have the timing curve of the animation as a
UnitCurve
, you can get its velocity at a particular point directly usingvelocity(at:)
. You would also need to know the animation’s duration, as well as the start and end points.Here is an example using that idea.