public final class

FlingAnimation

extends DynamicAnimation<FlingAnimation>

 java.lang.Object

androidx.dynamicanimation.animation.DynamicAnimation<FlingAnimation>

↳androidx.dynamicanimation.animation.FlingAnimation

Gradle dependencies

compile group: 'androidx.dynamicanimation', name: 'dynamicanimation', version: '1.1.0-alpha03'

  • groupId: androidx.dynamicanimation
  • artifactId: dynamicanimation
  • version: 1.1.0-alpha03

Artifact androidx.dynamicanimation:dynamicanimation:1.1.0-alpha03 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.dynamicanimation:dynamicanimation com.android.support:support-dynamic-animation

Androidx class mapping:

androidx.dynamicanimation.animation.FlingAnimation android.support.animation.FlingAnimation

Overview

Fling animation is an animation that continues an initial momentum (most often from gesture velocity) and gradually slows down. The fling animation will come to a stop when the velocity of the animation is below the threshold derived from DynamicAnimation.setMinimumVisibleChange(float), or when the value of the animation has gone beyond the min or max value defined via DynamicAnimation.setMinValue(float) or DynamicAnimation.setMaxValue(float). It is recommended to restrict the fling animation with min and/or max value, such that the animation can end when it goes beyond screen bounds, thus preserving CPU cycles and resources.

For example, you can create a fling animation that animates the translationX of a view:

 FlingAnimation flingAnim = new FlingAnimation(view, DynamicAnimation.TRANSLATION_X)
         // Sets the start velocity to -2000 (pixel/s)
         .setStartVelocity(-2000)
         // Optional but recommended to set a reasonable min and max range for the animation.
         // In this particular case, we set the min and max to -200 and 2000 respectively.
         .setMinValue(-200).setMaxValue(2000);
 flingAnim.start();
 

Summary

Fields
from DynamicAnimation<T>ALPHA, MIN_VISIBLE_CHANGE_ALPHA, MIN_VISIBLE_CHANGE_PIXELS, MIN_VISIBLE_CHANGE_ROTATION_DEGREES, MIN_VISIBLE_CHANGE_SCALE, ROTATION, ROTATION_X, ROTATION_Y, SCALE_X, SCALE_Y, SCROLL_X, SCROLL_Y, TRANSLATION_X, TRANSLATION_Y, TRANSLATION_Z, X, Y, Z
Constructors
publicFlingAnimation(FloatValueHolder floatValueHolder)

This creates a FlingAnimation that animates a FloatValueHolder instance.

publicFlingAnimation(java.lang.Object object, FloatPropertyCompat<java.lang.Object> property)

This creates a FlingAnimation that animates the property of the given object.

Methods
public floatgetFriction()

Returns the friction being set on the animation via FlingAnimation.setFriction(float).

public FlingAnimationsetFriction(float friction)

Sets the friction for the fling animation.

public FlingAnimationsetMaxValue(float maxValue)

Sets the max value of the animation.

public FlingAnimationsetMinValue(float minValue)

Sets the min value of the animation.

public FlingAnimationsetStartVelocity(float startVelocity)

Start velocity of the animation.

from DynamicAnimation<T>addEndListener, addUpdateListener, cancel, doAnimationFrame, getMinimumVisibleChange, isRunning, removeEndListener, removeUpdateListener, setMinimumVisibleChange, setStartValue, start
from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructors

public FlingAnimation(FloatValueHolder floatValueHolder)

This creates a FlingAnimation that animates a FloatValueHolder instance. During the animation, the FloatValueHolder instance will be updated via FloatValueHolder.setValue(float) each frame. The caller can obtain the up-to-date animation value via FloatValueHolder.getValue().

Note: changing the value in the FloatValueHolder via FloatValueHolder.setValue(float) outside of the animation during an animation run will not have any effect on the on-going animation.

Parameters:

floatValueHolder: the property to be animated

public FlingAnimation(java.lang.Object object, FloatPropertyCompat<java.lang.Object> property)

This creates a FlingAnimation that animates the property of the given object.

Parameters:

object: the Object whose property will be animated
property: the property to be animated

Methods

public FlingAnimation setFriction(float friction)

Sets the friction for the fling animation. The greater the friction is, the sooner the animation will slow down. When not set, the friction defaults to 1.

Parameters:

friction: the friction used in the animation

Returns:

the animation whose friction will be scaled

public float getFriction()

Returns the friction being set on the animation via FlingAnimation.setFriction(float). If the friction has not been set, the default friction of 1 will be returned.

Returns:

friction being used in the animation

public FlingAnimation setMinValue(float minValue)

Sets the min value of the animation. When a fling animation reaches the min value, the animation will end immediately. Animations will not animate beyond the min value.

Parameters:

minValue: minimum value of the property to be animated

Returns:

the Animation whose min value is being set

public FlingAnimation setMaxValue(float maxValue)

Sets the max value of the animation. When a fling animation reaches the max value, the animation will end immediately. Animations will not animate beyond the max value.

Parameters:

maxValue: maximum value of the property to be animated

Returns:

the Animation whose max value is being set

public FlingAnimation setStartVelocity(float startVelocity)

Start velocity of the animation. Default velocity is 0. Unit: pixel/second

A non-zero start velocity is required for a FlingAnimation. If no start velocity is set through FlingAnimation.setStartVelocity(float), the start velocity defaults to 0. In that case, the fling animation will consider itself done in the next frame.

Note when using a fixed value as the start velocity (as opposed to getting the velocity through touch events), it is recommended to define such a value in dp/second and convert it to pixel/second based on the density of the screen to achieve a consistent look across different screens.

To convert from dp/second to pixel/second:

 float pixelPerSecond = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond,
         getResources().getDisplayMetrics());
 

Parameters:

startVelocity: start velocity of the animation in pixel/second

Returns:

the Animation whose start velocity is being set

Source

/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.dynamicanimation.animation;

import androidx.annotation.FloatRange;

/**
 * <p>Fling animation is an animation that continues an initial momentum (most often from gesture
 * velocity) and gradually slows down. The fling animation will come to a stop when the velocity of
 * the animation is below the threshold derived from {@link #setMinimumVisibleChange(float)},
 * or when the value of the animation has gone beyond the min or max value defined via
 * {@link DynamicAnimation#setMinValue(float)} or {@link DynamicAnimation#setMaxValue(float)}.
 * It is recommended to restrict the fling animation with min and/or max value, such that the
 * animation can end when it goes beyond screen bounds, thus preserving CPU cycles and resources.
 *
 * <p>For example, you can create a fling animation that animates the translationX of a view:
 * <pre class="prettyprint">
 * FlingAnimation flingAnim = new FlingAnimation(view, DynamicAnimation.TRANSLATION_X)
 *         // Sets the start velocity to -2000 (pixel/s)
 *         .setStartVelocity(-2000)
 *         // Optional but recommended to set a reasonable min and max range for the animation.
 *         // In this particular case, we set the min and max to -200 and 2000 respectively.
 *         .setMinValue(-200).setMaxValue(2000);
 * flingAnim.start();
 * </pre>
 */
public final class FlingAnimation extends DynamicAnimation<FlingAnimation> {

    private final DragForce mFlingForce = new DragForce();

    /**
     * <p>This creates a FlingAnimation that animates a {@link FloatValueHolder} instance. During
     * the animation, the {@link FloatValueHolder} instance will be updated via
     * {@link FloatValueHolder#setValue(float)} each frame. The caller can obtain the up-to-date
     * animation value via {@link FloatValueHolder#getValue()}.
     *
     * <p><strong>Note:</strong> changing the value in the {@link FloatValueHolder} via
     * {@link FloatValueHolder#setValue(float)} outside of the animation during an
     * animation run will not have any effect on the on-going animation.
     *
     * @param floatValueHolder the property to be animated
     */
    public FlingAnimation(FloatValueHolder floatValueHolder) {
        super(floatValueHolder);
        mFlingForce.setValueThreshold(getValueThreshold());
    }

    /**
     * This creates a FlingAnimation that animates the property of the given object.
     *
     * @param object the Object whose property will be animated
     * @param property the property to be animated
     * @param <K> the class on which the property is declared
     */
    public <K> FlingAnimation(K object, FloatPropertyCompat<K> property) {
        super(object, property);
        mFlingForce.setValueThreshold(getValueThreshold());
    }

    /**
     * Sets the friction for the fling animation. The greater the friction is, the sooner the
     * animation will slow down. When not set, the friction defaults to 1.
     *
     * @param friction the friction used in the animation
     * @return the animation whose friction will be scaled
     * @throws IllegalArgumentException if the input friction is not positive
     */
    public FlingAnimation setFriction(
            @FloatRange(from = 0.0, fromInclusive = false) float friction) {
        if (friction <= 0) {
            throw new IllegalArgumentException("Friction must be positive");
        }
        mFlingForce.setFrictionScalar(friction);
        return this;
    }

    /**
     * Returns the friction being set on the animation via {@link #setFriction(float)}. If the
     * friction has not been set, the default friction of 1 will be returned.
     *
     * @return friction being used in the animation
     */
    public float getFriction() {
        return mFlingForce.getFrictionScalar();
    }

    /**
     * Sets the min value of the animation. When a fling animation reaches the min value, the
     * animation will end immediately. Animations will not animate beyond the min value.
     *
     * @param minValue minimum value of the property to be animated
     * @return the Animation whose min value is being set
     */
    @Override
    public FlingAnimation setMinValue(float minValue) {
        super.setMinValue(minValue);
        return this;
    }

    /**
     * Sets the max value of the animation. When a fling animation reaches the max value, the
     * animation will end immediately. Animations will not animate beyond the max value.
     *
     * @param maxValue maximum value of the property to be animated
     * @return the Animation whose max value is being set
     */
    @Override
    public FlingAnimation setMaxValue(float maxValue) {
        super.setMaxValue(maxValue);
        return this;
    }

    /**
     * Start velocity of the animation. Default velocity is 0. Unit: pixel/second
     *
     * <p>A <b>non-zero</b> start velocity is required for a FlingAnimation. If no start velocity is
     * set through {@link #setStartVelocity(float)}, the start velocity defaults to 0. In that
     * case, the fling animation will consider itself done in the next frame.
     *
     * <p>Note when using a fixed value as the start velocity (as opposed to getting the velocity
     * through touch events), it is recommended to define such a value in dp/second and convert it
     * to pixel/second based on the density of the screen to achieve a consistent look across
     * different screens.
     *
     * <p>To convert from dp/second to pixel/second:
     * <pre class="prettyprint">
     * float pixelPerSecond = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond,
     *         getResources().getDisplayMetrics());
     * </pre>
     *
     * @param startVelocity start velocity of the animation in pixel/second
     * @return the Animation whose start velocity is being set
     */
    @Override
    public FlingAnimation setStartVelocity(float startVelocity) {
        super.setStartVelocity(startVelocity);
        return this;
    }

    @Override
    boolean updateValueAndVelocity(long deltaT) {

        MassState state = mFlingForce.updateValueAndVelocity(mValue, mVelocity, deltaT);
        mValue = state.mValue;
        mVelocity = state.mVelocity;

        // When the animation hits the max/min value, consider animation done.
        if (mValue < mMinValue) {
            mValue = mMinValue;
            return true;
        }
        if (mValue > mMaxValue) {
            mValue = mMaxValue;
            return true;
        }

        if (isAtEquilibrium(mValue, mVelocity)) {
            return true;
        }
        return false;
    }

    @Override
    float getAcceleration(float value, float velocity) {
        return mFlingForce.getAcceleration(value, velocity);
    }

    @Override
    boolean isAtEquilibrium(float value, float velocity) {
        return value >= mMaxValue
                || value <= mMinValue
                || mFlingForce.isAtEquilibrium(value, velocity);
    }

    @Override
    void setValueThreshold(float threshold) {
        mFlingForce.setValueThreshold(threshold);
    }

    static final class DragForce implements Force {

        private static final float DEFAULT_FRICTION = -4.2f;

        // This multiplier is used to calculate the velocity threshold given a certain value
        // threshold. The idea is that if it takes >= 1 frame to move the value threshold amount,
        // then the velocity is a reasonable threshold.
        private static final float VELOCITY_THRESHOLD_MULTIPLIER = 1000f / 16f;
        private float mFriction = DEFAULT_FRICTION;
        private float mVelocityThreshold;

        // Internal state to hold a value/velocity pair.
        private final DynamicAnimation.MassState mMassState = new DynamicAnimation.MassState();

        void setFrictionScalar(float frictionScalar) {
            mFriction = frictionScalar * DEFAULT_FRICTION;
        }

        float getFrictionScalar() {
            return mFriction / DEFAULT_FRICTION;
        }

        MassState updateValueAndVelocity(float value, float velocity, long deltaT) {
            mMassState.mVelocity = (float) (velocity * Math.exp((deltaT / 1000f) * mFriction));
            mMassState.mValue = (float) (value - velocity / mFriction
                    + velocity / mFriction * Math.exp(mFriction * deltaT / 1000f));
            if (isAtEquilibrium(mMassState.mValue, mMassState.mVelocity)) {
                mMassState.mVelocity = 0f;
            }
            return mMassState;
        }

        @Override
        public float getAcceleration(float position, float velocity) {
            return velocity * mFriction;
        }

        @Override
        public boolean isAtEquilibrium(float value, float velocity) {
            return Math.abs(velocity) < mVelocityThreshold;
        }

        void setValueThreshold(float threshold) {
            mVelocityThreshold = threshold * VELOCITY_THRESHOLD_MULTIPLIER;
        }
    }

}