content: package com.wm.remusic.widget;
  
  import android.graphics.Bitmap;
  import android.graphics.Canvas;
  import android.graphics.Paint;
  import android.graphics.Rect;
  import android.graphics.drawable.BitmapDrawable;
  import android.support.annotation.Nullable;
  import android.support.v7.widget.RecyclerView;
  import android.util.Log;
  import android.view.MotionEvent;
  import android.view.View;
  
  
  public class DragSortRecycler extends RecyclerView.ItemDecoration implements RecyclerView.OnItemTouchListener {
  
      final String TAG = "DragSortRecycler";
  
      final boolean DEBUG = false;
      OnItemMovedListener moveInterface;
      @Nullable
      OnDragStateChangedListener dragStateChangedListener;
      Paint bgColor = new Paint();
      private int dragHandleWidth = 0;
      private int selectedDragItemPos = -1;
      private int fingerAnchorY;
      RecyclerView.OnScrollListener scrollListener = new RecyclerView.OnScrollListener() {
          @Override
          public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
              super.onScrollStateChanged(recyclerView, newState);
          }
  
          @Override
          public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
              super.onScrolled(recyclerView, dx, dy);
              debugLog("Scrolled: " + dx + " " + dy);
              fingerAnchorY -= dy;
          }
      };
      private int fingerY;
      private int fingerOffsetInViewY;
      private float autoScrollWindow = 0.1f;
      private float autoScrollSpeed = 0.5f;
      private BitmapDrawable floatingItem;
      private Rect floatingItemStatingBounds;
      private Rect floatingItemBounds;
      private float floatingItemAlpha = 0.5f;
      private int floatingItemBgColor = 0;
      private int viewHandleId = -1;
      private boolean isDragging;
  
      private void debugLog(String log) {
          if (DEBUG)
              Log.d(TAG, log);
      }
  
      public RecyclerView.OnScrollListener getScrollListener() {
          return scrollListener;
      }
  
      /*
       * Set the item move interface
       */
      public void setOnItemMovedListener(OnItemMovedListener swif) {
          moveInterface = swif;
      }
  
      public void setViewHandleId(int id) {
          viewHandleId = id;
      }
  
      public void setLeftDragArea(int w) {
          dragHandleWidth = w;
      }
  
      public void setFloatingAlpha(float a) {
          floatingItemAlpha = a;
      }
  
      public void setFloatingBgColor(int c) {
          floatingItemBgColor = c;
      }
  
      /*
       Set the window at top and bottom of list, must be between 0 and 0.5
       For example 0.1 uses the top and bottom 10% of the lists for scrolling
       */
      public void setAutoScrollWindow(float w) {
          autoScrollWindow = w;
      }
  
      /*
      Set the autoscroll speed, default is 0.5
       */
      public void setAutoScrollSpeed(float speed) {
          autoScrollSpeed = speed;
      }
  
      @Override
      public void getItemOffsets(Rect outRect, View view, RecyclerView rv, RecyclerView.State state) {
          super.getItemOffsets(outRect, view, rv, state);
  
          debugLog("getItemOffsets");
  
          debugLog("View top = " + view.getTop());
          if (selectedDragItemPos != -1) {
              int itemPos = rv.getChildLayoutPosition(view);
              debugLog("itemPos =" + itemPos);
  
              if (!canDragOver(itemPos)) {
                  return;
              }
  
              //Movement of finger
              float totalMovement = fingerY - fingerAnchorY;
  
              if (itemPos == selectedDragItemPos) {
                  view.setVisibility(View.INVISIBLE);
              } else {
                  //Make view visible incase invisible
                  view.setVisibility(View.VISIBLE);
  
                  //Find middle of the floatingItem
                  float floatMiddleY = floatingItemBounds.top + floatingItemBounds.height() / 2;
  
                  //Moving down the list
                  //These will auto-animate if the device continually sends touch motion events
                  // if (totalMovment>0)
                  {
                      if ((itemPos > selectedDragItemPos) && (view.getTop() < floatMiddleY)) {
                          float amountUp = (floatMiddleY - view.getTop()) / (float) view.getHeight();
                          //  amountUp *= 0.5f;
                          if (amountUp > 1)
                              amountUp = 1;
  
                          outRect.top = -(int) (floatingItemBounds.height() * amountUp);
                          outRect.bottom = (int) (floatingItemBounds.height() * amountUp);
                      }
  
                  }//Moving up the list
                  // else if (totalMovment < 0)
                  {
                      if ((itemPos < selectedDragItemPos) && (view.getBottom() > floatMiddleY)) {
                          float amountDown = ((float) view.getBottom() - floatMiddleY) / (float) view.getHeight();
                          //  amountDown *= 0.5f;
                          if (amountDown > 1)
                              amountDown = 1;
  
                          outRect.top = (int) (floatingItemBounds.height() * amountDown);
                          outRect.bottom = -(int) (floatingItemBounds.height() * amountDown);
                      }
                  }
              }
          } else {
              outRect.top = 0;
              outRect.bottom = 0;
              //Make view visible incase invisible
              view.setVisibility(View.VISIBLE);
          }
      }
  
      /**
       * Find the new position by scanning through the items on
       * screen and finding the positional relationship.
       * This *seems* to work, another method would be to use
       * getItemOffsets, but I think that could miss items?..
       */
      private int getNewPostion(RecyclerView rv) {
          int itemsOnScreen = rv.getLayoutManager().getChildCount();
  
          float floatMiddleY = floatingItemBounds.top + floatingItemBounds.height() / 2;
  
          int above = 0;
          int below = Integer.MAX_VALUE;
          for (int n = 0; n < itemsOnScreen; n++) //Scan though items on screen, however they may not
          {                                   // be in order!
  
              View view = rv.getLayoutManager().getChildAt(n);
  
              if (view.getVisibility() != View.VISIBLE)
                  continue;
  
              int itemPos = rv.getChildLayoutPosition(view);
  
              if (itemPos == selectedDragItemPos) //Don't check against itself!
                  continue;
  
              float viewMiddleY = view.getTop() + view.getHeight() / 2;
              if (floatMiddleY > viewMiddleY) //Is above this item
              {
                  if (itemPos > above)
                      above = itemPos;
              } else if (floatMiddleY <= viewMiddleY) //Is below this item
              {
                  if (itemPos < below)
                      below = itemPos;
              }
          }
          debugLog("above = " + above + " below = " + below);
  
          if (below != Integer.MAX_VALUE) {
              if (below < selectedDragItemPos) //Need to count itself
                  below++;
              return below - 1;
          } else {
              if (above < selectedDragItemPos)
                  above++;
  
              return above;
          }
      }
  
  
      @Override
      public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
          debugLog("onInterceptTouchEvent");
  
          //if (e.getAction() == MotionEvent.ACTION_DOWN)
          {
              View itemView = rv.findChildViewUnder(e.getX(), e.getY());
  
              if (itemView == null)
                  return false;
  
              boolean dragging = false;
  
              if ((dragHandleWidth > 0) && (e.getX() < dragHandleWidth)) {
                  dragging = true;
              } else if (viewHandleId != -1) {
                  //Find the handle in the list item
                  View handleView = itemView.findViewById(viewHandleId);
  
                  if (handleView == null) {
                      Log.e(TAG, "The view ID " + viewHandleId + " was not found in the RecycleView item");
                      return false;
                  }
  
                  //View should be visible to drag
                  if (handleView.getVisibility() != View.VISIBLE) {
                      return false;
                  }
  
                  //We need to find the relative position of the handle to the parent view
                  //Then we can work out if the touch is within the handle
                  int[] parentItemPos = new int[2];
                  itemView.getLocationInWindow(parentItemPos);
  
                  int[] handlePos = new int[2];
                  handleView.getLocationInWindow(handlePos);
  
                  int xRel = handlePos[0] - parentItemPos[0];
                  int yRel = handlePos[1] - parentItemPos[1];
  
                  Rect touchBounds = new Rect(itemView.getLeft() + xRel, itemView.getTop() + yRel,
                          itemView.getLeft() + xRel + handleView.getWidth(),
                          itemView.getTop() + yRel + handleView.getHeight()
                  );
  
                  if (touchBounds.contains((int) e.getX(), (int) e.getY()))
                      dragging = true;
  
                  debugLog("parentItemPos = " + parentItemPos[0] + " " + parentItemPos[1]);
                  debugLog("handlePos = " + handlePos[0] + " " + handlePos[1]);
              }
  
  
              if (dragging) {
                  debugLog("Started Drag");
  
                  setIsDragging(true);
  
                  floatingItem = createFloatingBitmap(itemView);
  
                  fingerAnchorY = (int) e.getY();
                  fingerOffsetInViewY = fingerAnchorY - itemView.getTop();
                  fingerY = fingerAnchorY;
  
                  selectedDragItemPos = rv.getChildLayoutPosition(itemView);
                  debugLog("selectedDragItemPos = " + selectedDragItemPos);
  
                  return true;
              }
          }
          return false;
      }
  
      @Override
      public void onRequestDisallowInterceptTouchEvent(boolean b) {
  
      }
  
      @Override
      public void onTouchEvent(RecyclerView rv, MotionEvent e) {
          debugLog("onTouchEvent");
  
          if ((e.getAction() == MotionEvent.ACTION_UP) ||
                  (e.getAction() == MotionEvent.ACTION_CANCEL)) {
              if ((e.getAction() == MotionEvent.ACTION_UP) && selectedDragItemPos != -1) {
                  int newPos = getNewPostion(rv);
                  if (moveInterface != null)
                      moveInterface.onItemMoved(selectedDragItemPos, newPos);
              }
  
              setIsDragging(false);
              selectedDragItemPos = -1;
              floatingItem = null;
              rv.invalidateItemDecorations();
              return;
          }
  
  
          fingerY = (int) e.getY();
  
          if (floatingItem != null) {
              floatingItemBounds.top = fingerY - fingerOffsetInViewY;
  
              if (floatingItemBounds.top < -floatingItemStatingBounds.height() / 2) //Allow half the view out the top
                  floatingItemBounds.top = -floatingItemStatingBounds.height() / 2;
  
              floatingItemBounds.bottom = floatingItemBounds.top + floatingItemStatingBounds.height();
  
              floatingItem.setBounds(floatingItemBounds);
          }
  
          //Do auto scrolling at end of list
          float scrollAmount = 0;
          if (fingerY > (rv.getHeight() * (1 - autoScrollWindow))) {
              scrollAmount = (fingerY - (rv.getHeight() * (1 - autoScrollWindow)));
          } else if (fingerY < (rv.getHeight() * autoScrollWindow)) {
              scrollAmount = (fingerY - (rv.getHeight() * autoScrollWindow));
          }
          debugLog("Scroll: " + scrollAmount);
  
          scrollAmount *= autoScrollSpeed;
          rv.scrollBy(0, (int) scrollAmount);
  
          rv.invalidateItemDecorations();// Redraw
      }
  
      private void setIsDragging(final boolean dragging) {
          if (dragging != isDragging) {
              isDragging = dragging;
              if (dragStateChangedListener != null) {
                  if (isDragging) {
                      dragStateChangedListener.onDragStart();
                  } else {
                      dragStateChangedListener.onDragStop();
                  }
              }
          }
      }
  
      public void setOnDragStateChangedListener(final OnDragStateChangedListener dragStateChangedListener) {
          this.dragStateChangedListener = dragStateChangedListener;
      }
  
      @Override
      public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
          if (floatingItem != null) {
              floatingItem.setAlpha((int) (255 * floatingItemAlpha));
              bgColor.setColor(floatingItemBgColor);
              c.drawRect(floatingItemBounds, bgColor);
              floatingItem.draw(c);
          }
      }
  
      /**
       * @param position
       * @return True if we can drag the item over this position, False if not.
       */
      protected boolean canDragOver(int position) {
          return true;
      }
  
      private BitmapDrawable createFloatingBitmap(View v) {
          floatingItemStatingBounds = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
          floatingItemBounds = new Rect(floatingItemStatingBounds);
  
          Bitmap bitmap = Bitmap.createBitmap(floatingItemStatingBounds.width(),
                  floatingItemStatingBounds.height(), Bitmap.Config.ARGB_8888);
          Canvas canvas = new Canvas(bitmap);
          v.draw(canvas);
  
          BitmapDrawable retDrawable = new BitmapDrawable(v.getResources(), bitmap);
          retDrawable.setBounds(floatingItemBounds);
  
          return retDrawable;
      }
  
      public interface OnItemMovedListener {
          void onItemMoved(int from, int to);
      }
  
  
      public interface OnDragStateChangedListener {
          void onDragStart();
  
          void onDragStop();
      }
  }