fyne-io / fyne

Cross platform GUI toolkit in Go inspired by Material Design
https://fyne.io/
Other
23.97k stars 1.34k forks source link

Sequential animations #2840

Open Max-Gording opened 2 years ago

Max-Gording commented 2 years ago

Although this feature is not extremely important for me, but I want to point out that at present there is no simple and clear API to create sequential animations, when each animation from the sequence is executed after the previous animation is completed. With today's API, animations by their writing look like they are executed sequentially, but in fact they are executed in parallel. Why in the Go language should I write as in JavaScript when I specifically want to get away from that? Unfortunately, this can no longer be fixed due to backward incompatibility.

Describe the solution you'd like to see:

It is proposed to have two objects for navigation sequences:

anim1=canvas.newParallelAnimation(
    rgbanim1 := canvas.newRGBAAnimation(),
    moveanim1 := canvas.newPositionAnimation(),
    ...
)
anim1.start()

anim2=canvas.newSequentialAnimation(
    rgbanim2 := canvas.newRGBAAnimation(),
    moveanim2 := canvas.newPositionAnimation(),
    ...
)
anim2.start()
Bluebugs commented 2 years ago

Thanks for opening this issues. To summarize discussion here. I do like Promise style of pattern for animation as it seems appropriate for chaining just interaction. @stuartmscott proposed to have a more dedicated API and we concluded our discussion on slack with the following proposal:

Further discussion are necessary to make sure that this would be enough. Another potential discussion to have here could be to add a more general purpose mechanism to chain action in Fyne as suggested by @andydotxyz and make sure that if we rule it out we are ok with it.

stuartmscott commented 2 years ago

Nice summary, thanks @Bluebugs.

OnComplete func() sounds like it could be useful even outside the context of sequential/parallel animations.

stuartmscott commented 2 years ago

Another idea:

AnimationSet interface could be introduced with two implementations (and corresponding constructors; NewSequentialAnimationSet & NewParallelAnimationSet).

AnimationSet could have OnComplete func(int) that is called after each animation in the set completes (OnComplete(0) for the first animation, OnComplete(1) for the second animation, and so on until OnComplete(N-1) for the last animation).

stuartmscott commented 2 years ago

Do we want to support a tree of animations/animationsets?

Unfortunately fyne.Animation is a struct, so if fyne.AnimationSet was introduced as a struct that embedded/extended fyne.Animation then it would have some fields which might not make sense.

Bluebugs commented 2 years ago

I think we will want to support a tree of animation. It will make for a more orthogonal/logic API.

The following field are present in fyne.Animation:

    AutoReverse bool
    Curve       AnimationCurve
    Duration    time.Duration
    RepeatCount int
    Tick        func(float32)

I think both Duration and Curve wouldn't apply on an AnimationSet. Would it be doable to move the rest in an AnimationBase and use that as an unnamed field in fyne.Animation ? I do not understand yet very well the API/ABI requirement in Go for stability.

andydotxyz commented 2 years ago

I think we will want to support a tree of animation. It will make for a more orthogonal/logic API.

I don't really understand this. What does a tree support that is important? What use-case are you envisaging?

I would not get too caught up on an animation set being a struct and/or looking like an animation - we could perhaps set them up as convenience functions / types that just comply with the Start()/Stop() semantic.

AnimationSet interface could be introduced with two implementations (and corresponding constructors; NewSequentialAnimationSet & NewParallelAnimationSet).

This looks like a clean approach :).

AnimationSet could have OnComplete func(int) that is called after each animation in the set completes (OnComplete(0) for the first animation, OnComplete(1) for the second animation, and so on until OnComplete(N-1) for the last animation).

I don't think this is necessary - OnComplete should be called on completion only. If developers want to get progress for individual animations then that should be referenced on the animation passed in, not reflected through additional info at the wrapping level (in my opinion).

Bluebugs commented 2 years ago

My understanting is that the consensus seems to converge toward:

andydotxyz commented 2 years ago

I think the use of interface in that message isn't quite right. What was agreed was that the new Sequential and Parallel constructors would return an *Animation instance, so that they can be used like any other animation, supporting the creation of "trees" where animation sets can be in animation sets.

andydotxyz commented 2 years ago

I don't remember discussing ParallelRace vs ParallelAll, just a single Parallel constructor, what is the difference @Bluebugs ?

Max-Gording commented 2 years ago

I agree with the solutions suggested by @Bluebugs. They provide clarity and flexibility.

The proposed constructor should return exactly *AnimationSet, because we are talking about a set of animations. An animation set should not be an animation, as they are different entities. But we must allow both single animations and sets of animations to be included in an AnimationSet, which will allow us to implement the proposal received from @andydotxyz

If I understand correctly, the solution shown will allow the same set of animations to run in different ways: sequentially or in parallel.

andydotxyz commented 2 years ago

An animation set should not be an animation, as they are different entities

If this is true then we need entirely new capabilities baked into all the drivers, as animations are passed into them to run smoothly. There are technical reasons where an AnimationSet would only be possible if it encapsulated the Animation.

andydotxyz commented 2 years ago

Notes from our discussion last week, apologies for the delays:

We would like to support animation trees (sets with other sets in them).

Animation set would need to be an animation - like returning a *Animation concrete type
constructor function could embed the detail in it's own ticker

Would OnComplete report child completion? - complicated by trees / sets of sets as input
Not needed, as we could attach to each Animation then use on individual animation if required
(avoids the 0..n parameter to OnComplete)