@Override
 public void onAnimationEnd(Animation animation) {
   if (mRefreshing) {
     mRefreshDrawable.start();
     if (mNotify) {
       if (mListener != null) {
         mListener.onRefresh();
       }
     }
   } else {
     mRefreshDrawable.stop();
     mRefreshView.setVisibility(View.GONE);
     animateOffsetToStartPosition();
   }
   mCurrentOffsetTop = mTarget.getTop();
 }
 private void setTargetOffsetTop(int offset, boolean requiresUpdate) {
   mRefreshView.bringToFront();
   //        mRefreshView.offsetTopAndBottom(offset);
   mTarget.offsetTopAndBottom(offset);
   mRefreshDrawable.offsetTopAndBottom(offset);
   mCurrentOffsetTop = mTarget.getTop();
   if (requiresUpdate && android.os.Build.VERSION.SDK_INT < 11) {
     invalidate();
   }
 }
 private void setRefreshing(boolean refreshing, final boolean notify) {
   if (mRefreshing != refreshing) {
     mNotify = notify;
     ensureTarget();
     mRefreshing = refreshing;
     if (mRefreshing) {
       mRefreshDrawable.setPercent(1f);
       animateOffsetToCorrectPosition();
     } else {
       animateOffsetToStartPosition();
     }
   }
 }
 public void setRefreshStyle(int type) {
   setRefreshing(false);
   switch (type) {
     case STYLE_MATERIAL:
       mRefreshDrawable = new MaterialDrawable(getContext(), this);
       break;
     case STYLE_CIRCLES:
       mRefreshDrawable = new CirclesDrawable(getContext(), this);
       break;
     case STYLE_WATER_DROP:
       mRefreshDrawable = new WaterDropDrawable(getContext(), this);
       break;
     case STYLE_RING:
       mRefreshDrawable = new RingDrawable(getContext(), this);
       break;
     default:
       throw new InvalidParameterException("Type does not exist");
   }
   mRefreshDrawable.setColorSchemeColors(mColorSchemeColors);
   mRefreshView.setImageDrawable(mRefreshDrawable);
 }
 @Override
 public void setBounds(int left, int top, int right, int bottom) {
   int w = right - left;
   super.setBounds(w / 2 - mDiameter / 2, top, w / 2 + mDiameter / 2, mDiameter + top);
 }
 @Override
 protected void onBoundsChange(Rect bounds) {
   super.onBoundsChange(bounds);
 }
 public void setColorSchemeColors(int[] colorSchemeColors) {
   mColorSchemeColors = colorSchemeColors;
   mRefreshDrawable.setColorSchemeColors(colorSchemeColors);
 }
 @Override
 public void onAnimationEnd(Animation animation) {
   mRefreshDrawable.stop();
   mRefreshView.setVisibility(View.GONE);
   mCurrentOffsetTop = mTarget.getTop();
 }
  @Override
  public boolean onTouchEvent(MotionEvent ev) {

    if (!mIsBeingDragged) {
      return super.onTouchEvent(ev);
    }

    final int action = MotionEventCompat.getActionMasked(ev);

    switch (action) {
      case MotionEvent.ACTION_MOVE:
        {
          final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
          if (pointerIndex < 0) {
            return false;
          }

          final float y = MotionEventCompat.getY(ev, pointerIndex);
          //                final float yDiff = Math.abs(y - mInitialMotionY);
          final float yDiff = y - mInitialMotionY;
          final float scrollTop = yDiff * DRAG_RATE;
          float originalDragPercent = scrollTop / mTotalDragDistance;
          if (originalDragPercent < 0) {
            return false;
          }
          float dragPercent = Math.min(1f, Math.abs(originalDragPercent));
          //                float adjustedPercent = (float) Math.max(dragPercent - .4, 0) * 5 / 3;
          //                    float adjustedPercent = dragPercent;
          float extraOS = Math.abs(scrollTop) - mTotalDragDistance;
          float slingshotDist = mSpinnerFinalOffset;
          float tensionSlingshotPercent =
              Math.max(0, Math.min(extraOS, slingshotDist * 2) / slingshotDist);
          float tensionPercent =
              (float) ((tensionSlingshotPercent / 4) - Math.pow((tensionSlingshotPercent / 4), 2))
                  * 2f;
          float extraMove = (slingshotDist) * tensionPercent * 2;
          int targetY = (int) ((slingshotDist * dragPercent) + extraMove);
          if (mRefreshView.getVisibility() != View.VISIBLE) {
            mRefreshView.setVisibility(View.VISIBLE);
          }
          if (scrollTop < mTotalDragDistance) {
            mRefreshDrawable.setPercent(dragPercent);
          }
          setTargetOffsetTop(targetY - mCurrentOffsetTop, true);
          break;
        }
      case MotionEventCompat.ACTION_POINTER_DOWN:
        final int index = MotionEventCompat.getActionIndex(ev);
        mActivePointerId = MotionEventCompat.getPointerId(ev, index);
        break;
      case MotionEventCompat.ACTION_POINTER_UP:
        onSecondaryPointerUp(ev);
        break;
      case MotionEvent.ACTION_UP:
      case MotionEvent.ACTION_CANCEL:
        {
          if (mActivePointerId == INVALID_POINTER) {
            return false;
          }
          final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
          final float y = MotionEventCompat.getY(ev, pointerIndex);
          final float overscrollTop = (y - mInitialMotionY) * DRAG_RATE;
          mIsBeingDragged = false;
          if (overscrollTop > mTotalDragDistance) {
            setRefreshing(true, true);
          } else {
            mRefreshing = false;
            animateOffsetToStartPosition();
          }
          mActivePointerId = INVALID_POINTER;
          return false;
        }
    }

    return true;
  }
 public void setRefreshDrawable(RefreshDrawable drawable) {
   setRefreshing(false);
   mRefreshDrawable = drawable;
   mRefreshDrawable.setColorSchemeColors(mColorSchemeColors);
   mRefreshView.setImageDrawable(mRefreshDrawable);
 }