-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Animation
Note
This document is archived as it refers to a design process.
Animation was implemented in the main drivers with helpers in fyne.io/fyne/v2/animation
package
Certain properties of the canvas
package may want to be animated.
Whilst this is possible using goroutines and calculations with lots of refresh methods this can be complicated and may not run optimally in line with the render process.
This proposal amims to make it much simpler to animate elements that will refresh with the renderer - with the ability to optimise internally for the graphical context.
Most of the animation basics are now on develop
branch, there are things we should explore, as follows:
- Auto-Reverse animation (loop or not)
- Cursor blink
- Button tap animation (replacing the simple delayed color change)
- Select tap and hover animation
- ProgressBarInfinite progress animation
- Debugging support - slowing frames or adding more to slow the animation in a debug mode
- Should we do some reflection to manage properties directly? (i.e.
NewColorPropertyAnimation(start, stop, propName, duration, func)
) (also called "storyboard animation" it seems)
Taken from Slack / Twitter
- Window Transitions
- Ripple effects
- Loaders
- Fade in from screen edge (mobile?), look at the C# UWP library
- Storyboard animation (see above)
- Tweening.
The start of animator is anything that uses, or embeds the Animator
struct.
Every animation has a duration and a Tick
callback that the framework will call, starting with a 0.0 parameter and ending with 1.0.
We can also set it to repeat. If false the amimation will end when duration lapses, at which point Tick parameter will be 1.0.
type Animator struct {
Duration time.Duration
Repeat bool
Tick func(float32)
}
func NewAnimator(d time.Duration, fn func(float32)) *Animator {
return &Animator{Duration: d, Tick: fn}
}
The basic Animator
is usable, but specific type versions on top are much more interesting, such as ColorAnimator
func NewColorAnimator(start, stop color.Color, d time.Duration, fn func(color.Color)) *Animator {
return &Animator{
Duration: d,
Tick: func (done float32) {
r1,g1,b1,a1 := start.RGBA()
r2,g2,b2,a2 := stop.RGBA()
rDiff := diff(r1, r2)
gDiff := diff(g1, g2)
bDiff := diff(b1, b2)
aDiff := diff(a1, a2)
fn(color.NRGBA{R: scale(r1, rDiff, done), G: scale(g1, gDiff, done), B: scale(b1, bDiff, done), A: scale(a1, aDiff, done)})
}}
}
The specific type of Animator above allows the user to specify a start and stop property and the tick callback will be of the same type. The duration is consistent with the generic type, and is used by the framework to schedule the changes.
To use the above animation you might do the following:
rect := NewRectangle(color.Black)
NewColorAnimation(color.Black, color.White, time.Second, func(c color.Color) {
rect.FillColor = c
rect.Refresh()
})
When an animation is included on a canvas object it's Tick() is called every frame from when the item becomes visible to when the duration elapses (or when the animation ends, if that is earlier). If repeat is set the duration will not lapse, but reset after duration and start again.
- Should we do some reflection to manage properties directly? (i.e.
NewColorPropertyAnimation(start, stop, propName, duration, func)
) - What types of things might people do? :)
-
Add Animation.Start() and Animation.Stop() to hide the details of canvas registration (rather like CanvasObject.Refresh() does).
-
Leaving CanvasObject specific registration for later, more object specific, API.
-
Leave out reflection for now - just pass functions until we learn more...
-
Split animations between those that run without context, and those that control a canvas object (as hinted above). Items controlling a canvasobject may need to be registered on a canvas, but the former don't so we can just register them on the driver. Such as
Driver.StartAnimation