Skip to content

Animation

Andy Williams edited this page Apr 2, 2024 · 9 revisions

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.

TODO

Most of the animation basics are now on develop branch, there are things we should explore, as follows:

Features planned

  • 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

Exploration

  • 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)

Requests

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.

Archive

Basics

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}
}

Specific types

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()
})

Runtime

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.

Questions

  • Should we do some reflection to manage properties directly? (i.e. NewColorPropertyAnimation(start, stop, propName, duration, func))
  • What types of things might people do? :)

Suggestions

  • 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