1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.launcher3.anim; 17 18 import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener; 19 import androidx.dynamicanimation.animation.FlingAnimation; 20 import androidx.dynamicanimation.animation.FloatPropertyCompat; 21 import androidx.dynamicanimation.animation.SpringAnimation; 22 import androidx.dynamicanimation.animation.SpringForce; 23 24 /** 25 * Given a property to animate and a target value and starting velocity, first apply friction to 26 * the fling until we pass the target, then apply a spring force to pull towards the target. 27 */ 28 public class FlingSpringAnim { 29 30 private static final float FLING_FRICTION = 1.5f; 31 private static final float SPRING_STIFFNESS = 200; 32 private static final float SPRING_DAMPING = 0.8f; 33 34 private final FlingAnimation mFlingAnim; 35 private SpringAnimation mSpringAnim; 36 37 private float mTargetPosition; 38 FlingSpringAnim(K object, FloatPropertyCompat<K> property, float startPosition, float targetPosition, float startVelocity, float minVisChange, float minValue, float maxValue, float springVelocityFactor, OnAnimationEndListener onEndListener)39 public <K> FlingSpringAnim(K object, FloatPropertyCompat<K> property, float startPosition, 40 float targetPosition, float startVelocity, float minVisChange, float minValue, 41 float maxValue, float springVelocityFactor, OnAnimationEndListener onEndListener) { 42 mFlingAnim = new FlingAnimation(object, property) 43 .setFriction(FLING_FRICTION) 44 // Have the spring pull towards the target if we've slowed down too much before 45 // reaching it. 46 .setMinimumVisibleChange(minVisChange) 47 .setStartVelocity(startVelocity) 48 .setMinValue(minValue) 49 .setMaxValue(maxValue); 50 mTargetPosition = targetPosition; 51 52 mFlingAnim.addEndListener(((animation, canceled, value, velocity) -> { 53 mSpringAnim = new SpringAnimation(object, property) 54 .setStartValue(value) 55 .setStartVelocity(velocity * springVelocityFactor) 56 .setSpring(new SpringForce(mTargetPosition) 57 .setStiffness(SPRING_STIFFNESS) 58 .setDampingRatio(SPRING_DAMPING)); 59 mSpringAnim.addEndListener(onEndListener); 60 mSpringAnim.animateToFinalPosition(mTargetPosition); 61 })); 62 } 63 getTargetPosition()64 public float getTargetPosition() { 65 return mTargetPosition; 66 } 67 updatePosition(float startPosition, float targetPosition)68 public void updatePosition(float startPosition, float targetPosition) { 69 mFlingAnim.setMinValue(Math.min(startPosition, targetPosition)) 70 .setMaxValue(Math.max(startPosition, targetPosition)); 71 mTargetPosition = targetPosition; 72 if (mSpringAnim != null) { 73 mSpringAnim.animateToFinalPosition(mTargetPosition); 74 } 75 } 76 start()77 public void start() { 78 mFlingAnim.start(); 79 } 80 end()81 public void end() { 82 mFlingAnim.cancel(); 83 if (mSpringAnim.canSkipToEnd()) { 84 mSpringAnim.skipToEnd(); 85 } 86 } 87 } 88