@Override
  protected void processOnMove(float currentX, float currentY, float offsetX, float offsetY) {

    if (currentY < mDownY) {
      super.processOnMove(currentX, currentY, offsetX, offsetY);
      return;
    }

    // distance from top
    final float scrollTop = (currentY - mDownY) * DRAG_RATE + mDownPos;
    final float currentDragPercent = scrollTop / mOneHeight;

    if (currentDragPercent < 0) {
      setOffset(offsetX, 0);
      return;
    }

    mCurrentDragPercent = currentDragPercent;

    // 0 ~ 1
    float boundedDragPercent = Math.min(1f, Math.abs(currentDragPercent));
    float extraOS = scrollTop - mOneHeight;

    // 0 ~ 2
    // if extraOS lower than 0, which means scrollTop lower than onHeight, tensionSlingshotPercent
    // will be 0.
    float tensionSlingshotPercent = Math.max(0, Math.min(extraOS, mOneHeight * 2) / mOneHeight);

    float tensionPercent =
        (float) ((tensionSlingshotPercent / 4) - Math.pow((tensionSlingshotPercent / 4), 2)) * 2f;
    float extraMove = (mOneHeight) * tensionPercent / 2;
    int targetY = (int) ((mOneHeight * boundedDragPercent) + extraMove);
    int change = targetY - getCurrentPosY();

    setOffset(currentX, change);
  }
 @Override
 public void onRelease() {
   super.onRelease();
   mReleasePos = getCurrentPosY();
   mReleasePercent = mCurrentDragPercent;
 }
 @Override
 public void setHeaderHeight(int height) {
   super.setHeaderHeight(height);
   mOneHeight = height * 4f / 5;
 }
 @Override
 public void onPressDown(float x, float y) {
   super.onPressDown(x, y);
   mDownY = y;
   mDownPos = getCurrentPosY();
 }