@Override
  public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    if (mPositionDataList == null || mPositionDataList.isEmpty()) {
      return;
    }

    // 计算锚点位置
    int currentPosition = Math.min(mPositionDataList.size() - 1, position);
    int nextPosition = Math.min(mPositionDataList.size() - 1, position + 1);
    PositionData current = mPositionDataList.get(currentPosition);
    PositionData next = mPositionDataList.get(nextPosition);

    mRect.left =
        current.mContentLeft
            - mHorizontalPadding
            + (next.mContentLeft - current.mContentLeft)
                * mEndInterpolator.getInterpolation(positionOffset);
    mRect.top = current.mContentTop - mVerticalPadding;
    mRect.right =
        current.mContentRight
            + mHorizontalPadding
            + (next.mContentRight - current.mContentRight)
                * mStartInterpolator.getInterpolation(positionOffset);
    mRect.bottom = current.mContentBottom + mVerticalPadding;

    if (!mRoundRadiusSet) {
      mRoundRadius = mRect.height() / 2;
    }

    invalidate();
  }
  private void updateWave() {
    float progress =
        Math.min(1f, (float) (SystemClock.uptimeMillis() - mStartTime) / mRippleAnimDuration);

    if (mState != STATE_RELEASE) {
      setRippleEffect(
          mRipplePoint.x,
          mRipplePoint.y,
          mMaxRippleRadius * mInInterpolator.getInterpolation(progress));

      if (progress == 1f) {
        mStartTime = SystemClock.uptimeMillis();
        if (mState == STATE_PRESS) setRippleState(STATE_HOVER);
        else {
          setRippleEffect(mRipplePoint.x, mRipplePoint.y, 0);
          setRippleState(STATE_RELEASE);
        }
      }
    } else {
      setRippleEffect(
          mRipplePoint.x,
          mRipplePoint.y,
          mMaxRippleRadius * mOutInterpolator.getInterpolation(progress));

      if (progress == 1f) setRippleState(STATE_OUT);
    }

    if (isRunning()) scheduleSelf(mUpdater, SystemClock.uptimeMillis() + ViewUtil.FRAME_DURATION);

    invalidateSelf();
  }
 @Override
 public float getInterpolation(float t) {
   if (t < 0.5) {
     return 0.5f * BounceEaseIn.getInterpolation(t * 2.0f);
   } else {
     return 0.5f * BounceEaseOut.getInterpolation(t * 2.0f - 1.0f) + 0.5f;
   }
 }
 @Override
 public void draw(Canvas canvas) {
   if (!mRunning) {
     if (mVisible) canvas.drawCircle(mX, mY, mRadius, mPaint);
   } else {
     float radius =
         mVisible
             ? mInInterpolator.getInterpolation(mAnimProgress) * mRadius
             : (1f - mOutInterpolator.getInterpolation(mAnimProgress)) * mRadius;
     canvas.drawCircle(mX, mY, radius, mPaint);
   }
 }
 public boolean calculate(final long currentTimeMillis) {
   if (mStartTime == NO_ANIMATION) return false;
   if (mStartTime == ANIMATION_START) {
     mStartTime = currentTimeMillis;
   }
   final int elapse = (int) (currentTimeMillis - mStartTime);
   final float x = Utils.clamp((float) elapse / mDuration, 0f, 1f);
   final Interpolator i = mInterpolator;
   onCalculate(i != null ? i.getInterpolation(x) : x);
   if (elapse >= mDuration) {
     mStartTime = NO_ANIMATION;
   }
   return mStartTime != NO_ANIMATION;
 }
 public boolean calculate(long paramLong) {
   if (this.mStartTime == -2L) ;
   do {
     return false;
     if (this.mStartTime == -1L) this.mStartTime = paramLong;
     int i = (int) (paramLong - this.mStartTime);
     float f = Utils.clamp(i / this.mDuration, 0.0F, 1.0F);
     Interpolator localInterpolator = this.mInterpolator;
     if (localInterpolator != null) f = localInterpolator.getInterpolation(f);
     onCalculate(f);
     if (i < this.mDuration) continue;
     this.mStartTime = -2L;
   } while (this.mStartTime == -2L);
   return true;
 }
示例#7
0
    public void run() {

      /**
       * Only set mStartTime if this is the first time we're starting, else actually calculate the Y
       * delta
       */
      if (mStartTime == -1) {
        mStartTime = System.currentTimeMillis();
      } else {

        /**
         * We do do all calculations in long to reduce software float calculations. We use 1000 as
         * it gives us good accuracy and small rounding errors
         */
        long normalizedTime =
            (1000 * (System.currentTimeMillis() - mStartTime)) / ANIMATION_DURATION_MS;
        normalizedTime = Math.max(Math.min(normalizedTime, 1000), 0);

        final int deltaY =
            Math.round(
                (mScrollFromY - mScrollToY)
                    * mInterpolator.getInterpolation(normalizedTime / 1000f));
        mCurrentY = mScrollFromY - deltaY;
        setHeaderScroll(mCurrentY);
      }

      // If we're not at the target Y, keep going...
      if (mContinueRunning && mScrollToY != mCurrentY) {
        mHandler.postDelayed(this, ANIMATION_FPS);
      }
    }
    @Override
    public void run() {

      /**
       * Only set mStartTime if this is the first time we're starting, else actually calculate the Y
       * delta
       */
      if (mStartTime == -1) {
        mStartTime = System.currentTimeMillis();
      } else {

        /**
         * We do do all calculations in long to reduce software float calculations. We use 1000 as
         * it gives us good accuracy and small rounding errors
         */
        long normalizedTime = (1000 * (System.currentTimeMillis() - mStartTime)) / mDuration;
        normalizedTime = Math.max(Math.min(normalizedTime, 1000), 0);

        final int deltaY =
            Math.round(
                (mScrollFromY - mScrollToY)
                    * mInterpolator.getInterpolation(normalizedTime / 1000f));
        mCurrentY = mScrollFromY - deltaY;
        setHeaderScroll(mCurrentY);
      }

      // If we're not at the target Y, keep going...
      if (mContinueRunning && mScrollToY != mCurrentY) {
        //				if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
        //					SDK16.postOnAnimation(PullToRefreshBase.this, this);
        //				} else {
        postDelayed(this, ANIMATION_DELAY);
        //				}
      }
    }
示例#9
0
    @Override
    public void run() {

      /**
       * Only set mStartTime if this is the first time we're starting, else actually calculate the Y
       * delta
       */
      if (mStartTime == -1) {
        mStartTime = System.currentTimeMillis();
      } else {

        /**
         * We do do all calculations in long to reduce software float calculations. We use 1000 as
         * it gives us good accuracy and small rounding errors
         */
        long normalizedTime = (1000 * (System.currentTimeMillis() - mStartTime)) / mDuration;
        normalizedTime = Math.max(Math.min(normalizedTime, 1000), 0);

        final int deltaY =
            Math.round(
                (mScrollFromY - mScrollToY)
                    * mInterpolator.getInterpolation(normalizedTime / 1000f));
        mCurrentY = mScrollFromY - deltaY;
        setHeaderScroll(mCurrentY);
      }

      // If we're not at the target Y, keep going...
      if (mContinueRunning && mScrollToY != mCurrentY) {
        ViewCompat.postOnAnimation(PullToRefreshBase.this, this);
      } else {
        if (null != mListener) {
          mListener.onSmoothScrollFinished();
        }
      }
    }
  private void updateSwapTargetTranslation(
      RecyclerView.ViewHolder draggingItem,
      RecyclerView.ViewHolder swapTargetItem,
      float translationPhase) {
    final View swapItemView = swapTargetItem.itemView;

    final int pos1 = draggingItem.getLayoutPosition();
    final int pos2 = swapTargetItem.getLayoutPosition();

    final Rect m1 = mDraggingItemMargins;
    final Rect d1 = mDraggingItemDecorationOffsets;
    final int h1 = mDraggingItemHeight + m1.top + m1.bottom + d1.top + d1.bottom;

    if (mSwapTargetTranslationInterpolator != null) {
      translationPhase = mSwapTargetTranslationInterpolator.getInterpolation(translationPhase);
    }

    if (pos1 > pos2) {
      // dragging item moving to upward
      ViewCompat.setTranslationY(swapItemView, translationPhase * h1);
    } else {
      // dragging item moving to downward
      ViewCompat.setTranslationY(swapItemView, (translationPhase - 1.0f) * h1);
    }
  }
 private void transform(View page, float position) {
   float interpolatorPosition;
   float translationX;
   int pageWidth = page.getWidth();
   if (mOutset <= 0) {
     mOutset = (int) (mOutsetFraction * page.getWidth());
   }
   if (position < 0) {
     interpolatorPosition = mInterpolator.getInterpolation(Math.abs(position));
     translationX = -mEvaluator.evaluate(interpolatorPosition, 0, (pageWidth - mOutset));
   } else {
     interpolatorPosition = mInterpolator.getInterpolation(position);
     translationX = mEvaluator.evaluate(interpolatorPosition, 0, (pageWidth - mOutset));
   }
   translationX += -page.getWidth() * position;
   page.setTranslationX(translationX);
 }
  private void updateQuery() {
    long curTime = SystemClock.uptimeMillis();
    mAnimTime = (float) (curTime - mLastProgressStateTime) / mTravelDuration;
    boolean requestUpdate =
        mRunState == RUN_STATE_STOPPING || mProgressPercent == 0 || mAnimTime < 1f;

    if (mAnimTime > 1f) {
      mLastProgressStateTime = Math.round(curTime - (mAnimTime - 1f) * mTravelDuration);
      mAnimTime -= 1f;
    }

    if (requestUpdate && mRunState != RUN_STATE_STOPPING) {
      Rect bounds = getBounds();
      int width = bounds.width();

      float maxWidth = mMaxLineWidth == 0 ? width * mMaxLineWidthPercent : mMaxLineWidth;
      float minWidth = mMinLineWidth == 0 ? width * mMinLineWidthPercent : mMinLineWidth;
      mLineWidth =
          mTransformInterpolator.getInterpolation(mAnimTime) * (minWidth - maxWidth) + maxWidth;
      if (mReverse) mLineWidth = -mLineWidth;

      mStartLine =
          mReverse
              ? mTransformInterpolator.getInterpolation(mAnimTime) * (width + minWidth)
              : ((1f - mTransformInterpolator.getInterpolation(mAnimTime)) * (width + minWidth)
                  - minWidth);
    }

    if (mRunState == RUN_STATE_STARTING) {
      if (curTime - mLastRunStateTime > mInAnimationDuration) mRunState = RUN_STATE_RUNNING;
    } else if (mRunState == RUN_STATE_STOPPING) {
      if (curTime - mLastRunStateTime > mOutAnimationDuration) {
        stop(false);
        return;
      }
    }

    if (isRunning()) {
      if (requestUpdate)
        scheduleSelf(mUpdater, SystemClock.uptimeMillis() + ViewUtil.FRAME_DURATION);
      else if (mRunState == RUN_STATE_RUNNING) mRunState = RUN_STATE_STARTED;
    }

    invalidateSelf();
  }
示例#13
0
 private void drawCircle(Canvas var1, float var2, float var3, int var4, float var5) {
   this.mPaint.setColor(var4);
   var1.save();
   var1.translate(var2, var3);
   var3 = INTERPOLATOR.getInterpolation(var5);
   var1.scale(var3, var3);
   var1.drawCircle(0.0F, 0.0F, var2, this.mPaint);
   var1.restore();
 }
 /**
  * Draws a circle centered in the view.
  *
  * @param canvas the canvas to draw on
  * @param cx the center x coordinate
  * @param cy the center y coordinate
  * @param color the color to draw
  * @param pct the percentage of the view that the circle should cover
  */
 private void drawCircle(Canvas canvas, float cx, float cy, int color, float pct) {
   mPaint.setColor(color);
   canvas.save();
   canvas.translate(cx, cy);
   float radiusScale = INTERPOLATOR.getInterpolation(pct);
   canvas.scale(radiusScale, radiusScale);
   canvas.drawCircle(0, 0, cx, mPaint);
   canvas.restore();
 }
示例#15
0
  /**
   * Computes the current zoom level, returning true if the zoom is still active and false if the
   * zoom has finished.
   *
   * @see android.widget.Scroller#computeScrollOffset()
   */
  public boolean computeZoom() {
    if (mFinished) {
      return false;
    }

    long tRTC = SystemClock.elapsedRealtime() - mStartRTC;
    if (tRTC >= mAnimationDurationMillis) {
      mFinished = true;
      mCurrentZoom = mEndZoom;
      applyZoomToCurrentRect(1f);
      return false;
    }

    float t = tRTC * 1f / mAnimationDurationMillis;
    mCurrentZoom = mEndZoom * mInterpolator.getInterpolation(t);
    applyZoomToCurrentRect(mInterpolator.getInterpolation(t));
    return true;
  }
示例#16
0
 private void drawCircle(
     Canvas paramCanvas, float paramFloat1, float paramFloat2, int paramInt, float paramFloat3) {
   this.mPaint.setColor(paramInt);
   paramCanvas.save();
   paramCanvas.translate(paramFloat1, paramFloat2);
   paramFloat2 = INTERPOLATOR.getInterpolation(paramFloat3);
   paramCanvas.scale(paramFloat2, paramFloat2);
   paramCanvas.drawCircle(0.0F, 0.0F, paramFloat1, this.mPaint);
   paramCanvas.restore();
 }
示例#17
0
 public static void getInterpolatorPoint(
     Point startPoint, Point endPoint, Point outPoint, float t) {
   if (outPoint == null) {
     return;
   }
   t = INTERPOLATOR.getInterpolation(t);
   t = Math.min(t, 1);
   t = Math.max(t, 0);
   outPoint.x = (int) (startPoint.x + (endPoint.x - startPoint.x) * t);
   outPoint.y = (int) (startPoint.y + (endPoint.y - startPoint.y) * t);
 }
示例#18
0
 private void update()
 {
     float f;
     float f2;
     f = Math.min((float)(AnimationUtils.currentAnimationTimeMillis() - mStartTime) / mDuration, 1.0F);
     f2 = mInterpolator.getInterpolation(f);
     mEdgeAlpha = mEdgeAlphaStart + (mEdgeAlphaFinish - mEdgeAlphaStart) * f2;
     mEdgeScaleY = mEdgeScaleYStart + (mEdgeScaleYFinish - mEdgeScaleYStart) * f2;
     mGlowAlpha = mGlowAlphaStart + (mGlowAlphaFinish - mGlowAlphaStart) * f2;
     mGlowScaleY = mGlowScaleYStart + (mGlowScaleYFinish - mGlowScaleYStart) * f2;
     if (f < 0.999F) goto _L2; else goto _L1
示例#19
0
  /**
   * Call this when you want to know the new location. If it returns true, the animation is not yet
   * finished.
   */
  public boolean computeScrollOffset() {
    if (mFinished) {
      return false;
    }

    int timePassed = (int) (AnimationUtils.currentAnimationTimeMillis() - mStartTime);

    if (timePassed < mDuration) {
      switch (mMode) {
        case SCROLL_MODE:
          final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal);
          mCurrX = mStartX + Math.round(x * mDeltaX);
          mCurrY = mStartY + Math.round(x * mDeltaY);
          break;
        case FLING_MODE:
          final float t = (float) timePassed / mDuration;
          final int index = (int) (NB_SAMPLES * t);
          float distanceCoef = 1.f;
          float velocityCoef = 0.f;
          if (index < NB_SAMPLES) {
            final float t_inf = (float) index / NB_SAMPLES;
            final float t_sup = (float) (index + 1) / NB_SAMPLES;
            final float d_inf = SPLINE_POSITION[index];
            final float d_sup = SPLINE_POSITION[index + 1];
            velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);
            distanceCoef = d_inf + (t - t_inf) * velocityCoef;
          }

          mCurrVelocity = velocityCoef * mDistance / mDuration * 1000.0f;

          mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX));
          // Pin to mMinX <= mCurrX <= mMaxX
          mCurrX = Math.min(mCurrX, mMaxX);
          mCurrX = Math.max(mCurrX, mMinX);

          mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));
          // Pin to mMinY <= mCurrY <= mMaxY
          mCurrY = Math.min(mCurrY, mMaxY);
          mCurrY = Math.max(mCurrY, mMinY);

          if (mCurrX == mFinalX && mCurrY == mFinalY) {
            mFinished = true;
          }

          break;
      }
    } else {
      mCurrX = mFinalX;
      mCurrY = mFinalY;
      mFinished = true;
    }
    return true;
  }
示例#20
0
 @Override
 public float getInterpolation(float input) {
   Interpolator interpolator = null;
   final float targetDuration = totalDuration * input;
   float durationSum = 0;
   float from = 0f;
   float to = 0f;
   float modifiedInput = 0f;
   for (int i = 0; i < interpolators.length; ++i) {
     float oldDurationSum = durationSum;
     float duration = durations[i];
     durationSum += duration;
     to = targets[i];
     if (targetDuration <= durationSum) {
       interpolator = interpolators[i];
       modifiedInput = (targetDuration - oldDurationSum) / duration;
       break;
     }
     from = to;
   }
   return from + (to - from) * interpolator.getInterpolation(modifiedInput);
 }
示例#21
0
 private void animationSleep(int j, Interpolator interpolator, float delta)
     throws InterruptedException {
   int interpolation = (int) (interpolator.getInterpolation(j / delta) * 10000000);
   int milliseconds = 0;
   if (interpolation >= MAX_SLEEP_NANOS) {
     milliseconds = interpolation / NANO_SECS;
     interpolation = interpolation % NANO_SECS;
   }
   try {
     Thread.sleep(milliseconds, interpolation);
   } catch (IllegalArgumentException ignore) {
   }
 }
示例#22
0
 void animateValue(float fraction) {
   fraction = mInterpolator.getInterpolation(fraction);
   mCurrentFraction = fraction;
   int numValues = mValues.length;
   for (PropertyValuesHolder mValue : mValues) {
     mValue.calculateValue(fraction);
   }
   if (mUpdateListeners != null) {
     int numListeners = mUpdateListeners.size();
     for (AnimatorUpdateListener mUpdateListener : mUpdateListeners) {
       mUpdateListener.onAnimationUpdate(this);
     }
   }
 }
示例#23
0
 /**
  * This method is called with the elapsed fraction of the animation during every animation frame.
  * This function turns the elapsed fraction into an interpolated fraction and then into an
  * animated value (from the evaluator. The function is called mostly during animation updates, but
  * it is also called when the <code>end()</code> function is called, to set the final value on the
  * property.
  *
  * <p>Overrides of this method must call the superclass to perform the calculation of the animated
  * value.
  *
  * @param fraction The elapsed fraction of the animation.
  */
 void animateValue(float fraction) {
   fraction = mInterpolator.getInterpolation(fraction);
   mCurrentFraction = fraction;
   int numValues = mValues.length;
   for (int i = 0; i < numValues; ++i) {
     mValues[i].calculateValue(fraction);
   }
   if (mUpdateListeners != null) {
     int numListeners = mUpdateListeners.size();
     for (int i = 0; i < numListeners; ++i) {
       mUpdateListeners.get(i).onAnimationUpdate(this);
     }
   }
 }
示例#24
0
 @Override
 public void run() {
   long now = AnimationUtils.currentAnimationTimeMillis();
   long duration = now - mStartTime;
   if (duration >= ANIMATION_DURATION) {
     mAlpha = 0.0f;
     invalidate();
     stop();
     return;
   } else {
     mAlpha = mInterpolator.getInterpolation(1 - duration / (float) ANIMATION_DURATION);
     invalidate();
   }
   postDelayed(mUpdater, FRAME_DURATION);
 }
        @Override
        public void run() {

          long currentTime = SystemClock.uptimeMillis();
          long diff = currentTime - mStartTime;
          if (diff < mDuration) {
            float interpolation = mInterpolator.getInterpolation((float) diff / (float) mDuration);
            scheduleSelf(mUpdater, currentTime + FRAME_DURATION);
            updateAnimation(interpolation);
          } else {
            unscheduleSelf(mUpdater);
            mRunning = false;
            updateAnimation(1f);
          }
        }
示例#26
0
  /**
   * Gets the animated value, given the elapsed fraction of the animation (interpolated by the
   * animation's interpolator) and the evaluator used to calculate in-between values. This function
   * maps the input fraction to the appropriate keyframe interval and a fraction between them and
   * returns the interpolated value. Note that the input fraction may fall outside the [0-1] bounds,
   * if the animation's interpolator made that happen (e.g., a spring interpolation that might send
   * the fraction past 1.0). We handle this situation by just using the two keyframes at the
   * appropriate end when the value is outside those bounds.
   *
   * @param fraction The elapsed fraction of the animation
   * @return The animated value.
   */
  public Object getValue(float fraction) {

    // Special-case optimization for the common case of only two keyframes
    if (mNumKeyframes == 2) {
      if (mInterpolator != null) {
        fraction = mInterpolator.getInterpolation(fraction);
      }
      return mEvaluator.evaluate(fraction, mFirstKeyframe.getValue(), mLastKeyframe.getValue());
    }
    if (fraction <= 0f) {
      final Keyframe nextKeyframe = mKeyframes.get(1);
      final /*Time*/ Interpolator interpolator = nextKeyframe.getInterpolator();
      if (interpolator != null) {
        fraction = interpolator.getInterpolation(fraction);
      }
      final float prevFraction = mFirstKeyframe.getFraction();
      float intervalFraction =
          (fraction - prevFraction) / (nextKeyframe.getFraction() - prevFraction);
      return mEvaluator.evaluate(
          intervalFraction, mFirstKeyframe.getValue(), nextKeyframe.getValue());
    } else if (fraction >= 1f) {
      final Keyframe prevKeyframe = mKeyframes.get(mNumKeyframes - 2);
      final /*Time*/ Interpolator interpolator = mLastKeyframe.getInterpolator();
      if (interpolator != null) {
        fraction = interpolator.getInterpolation(fraction);
      }
      final float prevFraction = prevKeyframe.getFraction();
      float intervalFraction =
          (fraction - prevFraction) / (mLastKeyframe.getFraction() - prevFraction);
      return mEvaluator.evaluate(
          intervalFraction, prevKeyframe.getValue(), mLastKeyframe.getValue());
    }
    Keyframe prevKeyframe = mFirstKeyframe;
    for (int i = 1; i < mNumKeyframes; ++i) {
      Keyframe nextKeyframe = mKeyframes.get(i);
      if (fraction < nextKeyframe.getFraction()) {
        final /*Time*/ Interpolator interpolator = nextKeyframe.getInterpolator();
        if (interpolator != null) {
          fraction = interpolator.getInterpolation(fraction);
        }
        final float prevFraction = prevKeyframe.getFraction();
        float intervalFraction =
            (fraction - prevFraction) / (nextKeyframe.getFraction() - prevFraction);
        return mEvaluator.evaluate(
            intervalFraction, prevKeyframe.getValue(), nextKeyframe.getValue());
      }
      prevKeyframe = nextKeyframe;
    }
    // shouldn't reach here
    return mLastKeyframe.getValue();
  }
  @Override
  public void computeRender(float renderProgress) {
    if (mRiverPath == null) {
      return;
    }

    if (mRiverMeasure == null) {
      mRiverMeasure = new PathMeasure(mRiverPath, false);
    }

    float fishProgress = FISH_INTERPOLATOR.getInterpolation(renderProgress);

    mRiverMeasure.getPosTan(mRiverMeasure.getLength() * fishProgress, mFishHeadPos, null);
    mFishRotateDegrees = calculateRotateDegrees(fishProgress);
  }
    @Override
    public final void run() {
      if (!mStarted) return;

      final long timeElapsed = AnimationUtils.currentAnimationTimeMillis() - mStartTime;
      mAnimationValue = mInterpolator.getInterpolation(timeElapsed / (float) mDuration);

      onAnimationUpdate();

      if (timeElapsed < mDuration) {
        Compat.postOnAnimation(mView, this);
      } else {
        if (++mRunCount < mRepeatCount || mRepeatCount == INFINITE) {
          restart();
        }
      }
    }
示例#29
0
  private void update() {
    long curTime = SystemClock.uptimeMillis();
    float progress = Math.min(1f, (float) (curTime - mStartTime) / mAnimDuration);
    float value = mInterpolator.getInterpolation(progress);

    mThumbPosition =
        mChecked ? (mStartPosition * (1 - value) + value) : (mStartPosition * (1 - value));

    if (progress == 1f) stopAnimation();

    if (mRunning) {
      if (getHandler() != null)
        getHandler().postAtTime(mUpdater, SystemClock.uptimeMillis() + ViewUtil.FRAME_DURATION);
      else stopAnimation();
    }

    invalidate();
  }
  /**
   * Call this when you want to know the new location. If it returns true, the animation is not yet
   * finished.
   */
  public boolean computeScrollOffset() {
    if (isFinished()) {
      return false;
    }

    switch (mMode) {
      case SCROLL_MODE:
        long time = AnimationUtils.currentAnimationTimeMillis();
        // Any scroller can be used for time, since they were started
        // together in scroll mode. We use X here.
        final long elapsedTime = time - mScrollerX.mStartTime;

        final int duration = mScrollerX.mDuration;
        if (elapsedTime < duration) {
          final float q = mInterpolator.getInterpolation(elapsedTime / (float) duration);
          mScrollerX.updateScroll(q);
          mScrollerY.updateScroll(q);
        } else {
          abortAnimation();
        }
        break;

      case FLING_MODE:
        if (!mScrollerX.mFinished) {
          if (!mScrollerX.update()) {
            if (!mScrollerX.continueWhenFinished()) {
              mScrollerX.finish();
            }
          }
        }

        if (!mScrollerY.mFinished) {
          if (!mScrollerY.update()) {
            if (!mScrollerY.continueWhenFinished()) {
              mScrollerY.finish();
            }
          }
        }

        break;
    }

    return true;
  }