public boolean tick() { if (!mRunning) { return false; } float t; if (mDuration <= 0) { t = 1; } else { t = (float) (SystemClock.elapsedRealtime() - mStartTime) * 1f / mDuration; if (t >= 1) { t = 1; } } if (t >= 1) { // Ended mRunning = false; mCurrentValue = mEndValue; if (mEndCallback != null) { mEndCallback.run(); } return false; } // Still running; compute value mCurrentValue = mStartValue + mInterpolator.getInterpolation(t) * (mEndValue - mStartValue); mRunning = true; return true; }
@Override public void draw(Canvas canvas) { int targetGradientAlpha = 0, targetColor = 0; if (mMode == MODE_TRANSLUCENT) { targetGradientAlpha = 0xff; } else if (mMode == MODE_SEMI_TRANSPARENT) { targetColor = mSemiTransparent; } else { targetColor = mOpaque; } if (!mAnimating) { mColor = targetColor; mGradientAlpha = targetGradientAlpha; } else { final long now = SystemClock.elapsedRealtime(); if (now >= mEndTime) { mAnimating = false; mColor = targetColor; mGradientAlpha = targetGradientAlpha; } else { final float t = (now - mStartTime) / (float) (mEndTime - mStartTime); final float v = Math.max(0, Math.min(mInterpolator.getInterpolation(t), 1)); mGradientAlpha = (int) (v * targetGradientAlpha + mGradientAlphaStart * (1 - v)); mColor = Color.argb( (int) (v * Color.alpha(targetColor) + Color.alpha(mColorStart) * (1 - v)), (int) (v * Color.red(targetColor) + Color.red(mColorStart) * (1 - v)), (int) (v * Color.green(targetColor) + Color.green(mColorStart) * (1 - v)), (int) (v * Color.blue(targetColor) + Color.blue(mColorStart) * (1 - v))); } } if (mGradientAlpha > 0) { mGradient.setAlpha(mGradientAlpha); mGradient.draw(canvas); } if (Color.alpha(mColor) > 0) { canvas.drawColor(mColor); } if (mAnimating) { invalidateSelf(); // keep going } }
/** * This method animates a view at the end of a drag and drop animation. * * @param view The view to be animated. This view is drawn directly into DragLayer, and so doesn't * need to be a child of DragLayer. * @param from The initial location of the view. Only the left and top parameters are used. * @param to The final location of the view. Only the left and top parameters are used. This * location doesn't account for scaling, and so should be centered about the desired final * location (including scaling). * @param finalAlpha The final alpha of the view, in case we want it to fade as it animates. * @param finalScale The final scale of the view. The view is scaled about its center. * @param duration The duration of the animation. * @param motionInterpolator The interpolator to use for the location of the view. * @param alphaInterpolator The interpolator to use for the alpha of the view. * @param onCompleteRunnable Optional runnable to run on animation completion. * @param fadeOut Whether or not to fade out the view once the animation completes. If true, the * runnable will execute after the view is faded out. * @param anchorView If not null, this represents the view which the animated view stays anchored * to in case scrolling is currently taking place. Note: currently this is only used for the X * dimension for the case of the workspace. */ public void animateView( final DragView view, final Rect from, final Rect to, final float finalAlpha, final float initScaleX, final float initScaleY, final float finalScaleX, final float finalScaleY, int duration, final Interpolator motionInterpolator, final Interpolator alphaInterpolator, final Runnable onCompleteRunnable, final int animationEndStyle, View anchorView) { // Calculate the duration of the animation based on the object's distance final float dist = (float) Math.sqrt(Math.pow(to.left - from.left, 2) + Math.pow(to.top - from.top, 2)); final Resources res = getResources(); final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist); // If duration < 0, this is a cue to compute the duration based on the distance if (duration < 0) { duration = res.getInteger(R.integer.config_dropAnimMaxDuration); if (dist < maxDist) { duration *= mCubicEaseOutInterpolator.getInterpolation(dist / maxDist); } duration = Math.max(duration, res.getInteger(R.integer.config_dropAnimMinDuration)); } // Fall back to cubic ease out interpolator for the animation if none is specified TimeInterpolator interpolator = null; if (alphaInterpolator == null || motionInterpolator == null) { interpolator = mCubicEaseOutInterpolator; } // Animate the view final float initAlpha = view.getAlpha(); final float dropViewScale = view.getScaleX(); AnimatorUpdateListener updateCb = new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { final float percent = (Float) animation.getAnimatedValue(); final int width = view.getMeasuredWidth(); final int height = view.getMeasuredHeight(); float alphaPercent = alphaInterpolator == null ? percent : alphaInterpolator.getInterpolation(percent); float motionPercent = motionInterpolator == null ? percent : motionInterpolator.getInterpolation(percent); float initialScaleX = initScaleX * dropViewScale; float initialScaleY = initScaleY * dropViewScale; float scaleX = finalScaleX * percent + initialScaleX * (1 - percent); float scaleY = finalScaleY * percent + initialScaleY * (1 - percent); float alpha = finalAlpha * alphaPercent + initAlpha * (1 - alphaPercent); float fromLeft = from.left + (initialScaleX - 1f) * width / 2; float fromTop = from.top + (initialScaleY - 1f) * height / 2; int x = (int) (fromLeft + Math.round(((to.left - fromLeft) * motionPercent))); int y = (int) (fromTop + Math.round(((to.top - fromTop) * motionPercent))); int xPos = x - mDropView.getScrollX() + (mAnchorView != null ? (mAnchorViewInitialScrollX - mAnchorView.getScrollX()) : 0); int yPos = y - mDropView.getScrollY(); mDropView.setTranslationX(xPos); mDropView.setTranslationY(yPos); mDropView.setScaleX(scaleX); mDropView.setScaleY(scaleY); mDropView.setAlpha(alpha); } }; animateView( view, updateCb, duration, interpolator, onCompleteRunnable, animationEndStyle, anchorView); }