content: package com.hzl.pulltorefresh.refresh.indicator;
  
  public class PtrTensionIndicator extends PtrIndicator {
  
      private float DRAG_RATE = 0.5f;
      private float mDownY;
      private float mDownPos;
      private float mOneHeight = 0;
  
      private float mCurrentDragPercent;
  
      private int mReleasePos;
      private float mReleasePercent = -1;
  
      @Override
      public void onPressDown(float x, float y) {
          super.onPressDown(x, y);
          mDownY = y;
          mDownPos = getCurrentPosY();
      }
  
      @Override
      public void onRelease() {
          super.onRelease();
          mReleasePos = getCurrentPosY();
          mReleasePercent = mCurrentDragPercent;
      }
  
      @Override
      public void onUIRefreshComplete() {
          mReleasePos = getCurrentPosY();
          mReleasePercent = getOverDragPercent();
      }
  
      @Override
      public void setHeaderHeight(int height) {
          super.setHeaderHeight(height);
          mOneHeight = height * 4f / 5;
      }
  
      @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);
      }
  
      private float offsetToTarget(float scrollTop) {
  
          // distance from top
          final float currentDragPercent = scrollTop / mOneHeight;
  
          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 mOneHeight, 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);
  
          return 0;
      }
  
      @Override
      public int getOffsetToKeepHeaderWhileLoading() {
          return getOffsetToRefresh();
      }
  
      @Override
      public int getOffsetToRefresh() {
          return (int) mOneHeight;
      }
  
      public float getOverDragPercent() {
          if (isUnderTouch()) {
              return mCurrentDragPercent;
          } else {
              if (mReleasePercent <= 0) {
                  return 1.0f * getCurrentPosY() / getOffsetToKeepHeaderWhileLoading();
              }
              // after release
              return mReleasePercent * getCurrentPosY() / mReleasePos;
          }
      }
  }
  