@Override
 public int clampViewPositionVertical(final View child, final int top, final int dy) {
   final int current = mDrawer.getHeaderTop();
   if (!Float.isNaN(mDx) && mDrawer.isValidScroll(mDx, dy)) {
     mScrollingHeaderByHelper = false;
     return current;
   }
   if (dy > 0 && mDrawer.canScrollCallback(-dy) && mDrawer.isTouchingScrollableContent()) {
     if (!mDrawer.isUsingDragHelper()) {
       // Scrolling up while list still has space to scroll, so make header still
       mScrollingHeaderByHelper = false;
       return current;
     } else {
       mDrawer.scrollByCallback(-dy);
       mScrollingHeaderByHelper = false;
       return current;
     }
   }
   final int min = mDrawer.getHeaderTopMinimum(), max = mDrawer.getHeaderTopMaximum();
   if (top < min && mDrawer.isTouchingScrollableContent() && mDrawer.isUsingDragHelper()) {
     mDrawer.scrollByCallback(-dy);
   }
   mScrollingHeaderByHelper = true;
   return MathUtils.clamp(top, min, max);
 }
 @Override
 public void onViewDragStateChanged(int state) {
   switch (state) {
     case ViewDragHelper.STATE_SETTLING:
     case ViewDragHelper.STATE_DRAGGING:
       {
         mScrollingHeaderByHelper = false;
         break;
       }
     case ViewDragHelper.STATE_IDLE:
       {
         if (mTime > 0 && !Float.isNaN(mVelocity)) {
           final float velocity = mVelocity;
           if (velocity < 0 && mDrawer.getHeaderTop() <= mDrawer.getHeaderTopMinimum()) {
             mDrawer.flingCallback(-velocity);
           }
         }
         mTime = -1;
         mDx = Float.NaN;
         mDy = Float.NaN;
         mVelocity = Float.NaN;
         mScrollingHeaderByHelper = false;
         break;
       }
   }
   super.onViewDragStateChanged(state);
 }
 @Override
 public void onViewReleased(View releasedChild, float xvel, float yvel) {
   mDrawer.mDragHelper.flingCapturedView(
       mDrawer.getPaddingLeft(),
       mDrawer.getHeaderTopMinimum(),
       mDrawer.getPaddingLeft(),
       mDrawer.getHeaderTopMaximum());
   ViewCompat.postInvalidateOnAnimation(mDrawer);
 }
 @Override
 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
   final int top = mDrawer.getHeaderTop(), min = mDrawer.getHeaderTopMinimum();
   final boolean showingFullContent = top <= min, flingUp = velocityY < 0;
   final boolean verticalFling = Math.abs(velocityY) > Math.abs(velocityX);
   if (!verticalFling) return true;
   if (showingFullContent) {
     if (flingUp) {
       // Fling list up when showing full content
       if (mDrawer.isScrollingContentCallback()) {
         mDrawer.flingCallback(-velocityY);
       }
     } else {
       // Fling down when list reached top and not dragging user ViewDragHelper,
       // so we fling header down here
       if (!mDrawer.canScrollCallback(1) && !mDrawer.isUsingDragHelper()) {
         mDrawer.flingHeader(velocityY);
       }
     }
   } else {
     // Header still visible
   }
   return true;
 }
 @Override
 public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
   if (!mDrawer.isUsingDragHelper() && mDrawer.isValidScroll(distanceY, distanceX)) {
     final int offset = mDrawer.getHeaderTop(), min = mDrawer.getHeaderTopMinimum();
     if (!mDrawer.canScrollCallback(-1)) {
       if (distanceY < 0) {
         if (!mDrawer.isScrollingHeaderByHelper()) {
           mDrawer.offsetHeaderBy(Math.round(-distanceY));
         }
         mDrawer.setScrollingHeaderByGesture(true);
       } else if (distanceY > 0 && offset > min) {
         // Scrolling up when scrolling to list top, so we cancel touch event and scrolling
         // header up
         mDrawer.cancelTouchCallback();
         if (!mDrawer.isScrollingHeaderByHelper()) {
           mDrawer.offsetHeaderBy(Math.round(-distanceY));
         }
       } else if (offset <= min) {
         mDrawer.scrollByCallback(-distanceX);
       }
     }
   }
   return true;
 }