Skip to content

Performance API refactor #215

Description

@FlutterIssues

Issue by Hixie
Wednesday Oct 21, 2015 at 16:48 GMT
Originally opened as https://github.com/flutter/engine/issues/1708


An AnimatedPerformance is a ticker plus forward()/reverse() methods, and exposes a value in the range 0..1 plus a direction and a change notification API.

A Curve should just be something that takes a value in the range 0..1 plus a direction and a change notification API, and exposes a value in the range 0..1 plus a direction and a change notification API (that it transparently forwards to the input's change notification API).

This would mean we would only need to accept one type rather than accepting a performance plus a curve everywhere, and consumers could chain performances and curves however they wanted. It would also mean you could have a "performance" that was slaved to another kind of input than a ticker.

Activity

  1. added this to the milestone on Nov 9, 2015
  2. added
    frameworkflutter/packages/flutter repository. See also f: labels.
    on Nov 9, 2015
  3. Hixie commented on Nov 18, 2015

    @Hixie
    Contributor

    and Simulations too!

  4. Hixie commented on Dec 2, 2015

    @Hixie
    Contributor

    PerformanceView should lose updateVariable and curveDirection.
    AnimatedValue should lose its curves. Instead it takes a PerformanceView, begin, and end, and just asks the performance view it's given for its progress and linearly lerps from begin to end with that value.
    Curves are then done as new classes that implement PerformanceView and take a PerformanceView. One of these classes would just apply a curve to the parent's value, forwarding all other calls through. Another would take two curves and remember what direction it's going in.
    Transitions would just take one argument, not a performanceview and a variable.

  5. changed the title [-] Curve and Performance should expose the same API[/-] [+]Performance API refactor[/+] on Dec 2, 2015
  6. self-assigned this
    on Dec 5, 2015
  7. Hixie commented on Dec 30, 2015

    @Hixie
    Contributor

    see also #216 #253 #218

  8. Hixie commented on Jan 6, 2016

    @Hixie
    Contributor

    Some ideas:

    abstract class Watchable {
      void addListener(...);
      void removeListener(...);
      void addStatusListener(...);
      void removeStatusListener(...);
      Status get status;
      Direction get direction;
    }
    
    abstract class HasProgress extends Watchable {
      double get progress;
      void attach(Attachable child) {
        child._setParent(this);
      }
    }
    
    abstract class Attachable {
      HasProgress get parent => _parent;
      HasProgress _parent;
      void _setParent(HasProgress parent) {
        assert(!attached);
        _parent = parent;
      }
      bool get attached => _parent != null;
    }
    
    abstract class HasValue<T> {
      T get value;
    }
    
    
    // concrete classes
    
    class AController with HasProgress {
      // owns a ticker, simulation, etc
      // play, forward, reverse, fling, etc
      // progress updated by ticker
    }
    
    class ACurve with HasProgress, Attachable {
      // curve, reverseCurve
      double get progress => parent.progress adjusted by relevant curve;
    }
    
    class AValue<T extends dynamic> with Watchable, Attachable implements HasValue<T> {
      // begin, end
      T get value => lerp(parent.progress, begin, end);
    }
    
    class ARectValue with Watchable, Attachable implements HasValue<Rect> {
      // begin, end
      Rect get value => Rect.lerp(parent.progress, begin, end);
    }
    
    class ADoubleValue with HasProgress, Attachable implements HasValue<double> {
      // begin, end
      double get value => lerpDouble(parent.progress, begin, end);
      double get progress => value;
    }

    So:

    class ProgressIndicatorAppState extends State<ProgressIndicatorApp> {
      void initState() {
        super.initState();
        valueController = new AController(duration: const Duration(milliseconds: 1500));
        valueAnimation = valueController.attach(new ACurve(
          curve: const Interval(0.0, 0.9, curve: Curves.ease),
          reverseCurve: Curves.ease
        )).attach(new ADoubleValue(
          begin: 0.0,
          end: 1.0
        ));
        valueController.addStatusListener((PerformanceStatus status) {
          if (status == PerformanceStatus.dismissed
              || status == PerformanceStatus.completed)
            reverseValueAnimationDirection();
        });
        valueController.play(valueAnimationDirection);
      }
      // ...
      // use valueAnimation.value to get the current value in the build function
    
  9. Hixie commented on Jan 9, 2016

    @Hixie
    Contributor

    The plan is to try implementing the suggestion above and then comparing it to the approach in #1078 to make a decision on how to proceed.

  10. krisgiesing commented on Jan 11, 2016

    @krisgiesing
    Contributor

    I'm a little unsure about the handling of direction in the current APIs. Direction makes sense for things that are driven by time, but if the driver is arbitrary, then direction makes less sense. I.e. you could have a Curve that maps randomly distributed inputs to randomly distributed outputs and still have the notion of "shape", but "direction" is kind of meaningless.

    I believe Performance is the earliest part of the class hierarchy where time is introduced, so I'm wondering if direction as a concept should be removed from everything above it (i.e. removed from PerformanceView, and by virtue of the new inheritance strategy, from Curve).

  11. abarth commented on Jan 11, 2016

    @abarth
    Contributor

    Interesting idea. We should look at the clients of PerformanceView to see how many of them care about direction. The hero transitions do (in order to decide which heros to select). I'm not sure what else cares.

  12. Hixie commented on Jan 11, 2016

    @Hixie
    Contributor

    One big use of direction is having a different curve when going forward
    than going backward. The other big use is knowing if you've reached the
    "dismissed" state vs the "completed" state (though that's built into
    Performance itself).

    On Mon, Jan 11, 2016 at 3:35 PM Adam Barth [email protected] wrote:

    Interesting idea. We should look at the clients of PerformanceView to see
    how many of them care about direction. The hero transitions do (in order to
    decide which heros to select). I'm not sure what else cares.

    —
    Reply to this email directly or view it on GitHub
    #215 (comment).

  13. krisgiesing commented on Jan 12, 2016

    @krisgiesing
    Contributor

    I'm looking at these APIs at the moment with an eye toward having a PerformanceView that's driven by input events. In that context it's a little unclear why direction is useful. You reach the dismissed state if you end at 0.0 progress and the completed state if you end at 1.0 progress, but in the middle you might drift back and forth. In that context having two different curves for going forward vs. backward is a little weird because you would (in the general case) have two different possible outputs for a given mid-interval input, so you'd get discontinuities if you switched back and forth.

  14. krisgiesing commented on Jan 12, 2016

    @krisgiesing
    Contributor

    Note, I'm not saying the use cases you mention aren't valuable, just that they're not necessarily universal; so they would go better in subclass(es) than base class(es).

  15. Hixie commented on Jan 12, 2016

    @Hixie
    Contributor

    As implemented, you never switch curves in the middle. You only switch curves if you hit the end.

  16. github-actions commented on Aug 17, 2021

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  17. locked as resolved and limited conversation to collaborators on Aug 17, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

a: animationAnimation APIsc: contributor-productivityTeam-specific productivity, code health, technical debt.frameworkflutter/packages/flutter repository. See also f: labels.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions