content: package com.anarchy.classify;
  
  import android.animation.Animator;
  import android.animation.AnimatorListenerAdapter;
  import android.animation.ObjectAnimator;
  import android.animation.PropertyValuesHolder;
  import android.annotation.TargetApi;
  import android.app.Dialog;
  import android.content.ClipData;
  import android.content.Context;
  import android.content.DialogInterface;
  import android.content.res.TypedArray;
  import android.graphics.PixelFormat;
  import android.graphics.drawable.Drawable;
  import android.os.Build;
  import android.os.SystemClock;
  import android.support.annotation.IntDef;
  import android.support.annotation.NonNull;
  import android.support.v4.view.GestureDetectorCompat;
  import android.support.v4.view.MotionEventCompat;
  import android.support.v4.view.ViewCompat;
  import android.support.v7.widget.GridLayoutManager;
  import android.support.v7.widget.RecyclerView;
  import android.util.AttributeSet;
  import android.view.DragEvent;
  import android.view.GestureDetector;
  import android.view.Gravity;
  import android.view.MotionEvent;
  import android.view.VelocityTracker;
  import android.view.View;
  import android.view.ViewGroup;
  import android.view.Window;
  import android.view.WindowManager;
  import android.view.animation.Interpolator;
  import android.widget.FrameLayout;
  
  import com.anarchy.classify.adapter.BaseMainAdapter;
  import com.anarchy.classify.adapter.BaseSubAdapter;
  import com.anarchy.classify.callback.BaseCallBack;
  import com.anarchy.classify.callback.MainRecyclerViewCallBack;
  import com.anarchy.classify.callback.SubRecyclerViewCallBack;
  import com.anarchy.classify.simple.BaseSimpleAdapter;
  import com.anarchy.classify.util.L;
  
  import java.lang.annotation.Retention;
  import java.lang.annotation.RetentionPolicy;
  import java.util.ArrayList;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Queue;
  
  /**
   * <p>
   * Date: 16/6/1 14:16
   * Author: rsshinide38@163.com
   * <p>
   */
  public class ClassifyView extends FrameLayout {
  
      /**
       * 不做处理的状态
       */
      public static final int MOVE_STATE_NONE = 0;
      /**
       * 当前状态为 可移动
       */
      public static final int MOVE_STATE_MOVE = 1;
      /**
       * 当前状态为 可合并
       */
      public static final int MOVE_STATE_MERGE = 2;
  
  
      public static final int STATE_IDLE = 0;
      public static final int STATE_DRAG = 1;
      public static final int STATE_SETTLE = 2;
  
      public static final int UNKNOWN_REGION = 0;
      public static final int IN_MAIN_REGION = 1;
      public static final int IN_SUB_REGION = 2;
      public static final int SUB_REGION_LEAVE_TYPE = 0x10;
  
  
      public static final int LEFT_TOP = 0;
      public static final int RIGHT_TOP = 1;
      public static final int LEFT_BOTTOM = 2;
      public static final int RIGHT_BOTTOM = 3;
      public static final int CENTER = 4;
  
      @IntDef({MOVE_STATE_NONE, MOVE_STATE_MOVE, MOVE_STATE_MERGE})
      @Retention(RetentionPolicy.SOURCE)
      public @interface MoveState {
      }
      @IntDef(value = {IN_MAIN_REGION,IN_SUB_REGION, UNKNOWN_REGION,SUB_REGION_LEAVE_TYPE},flag = true)
      @Retention(RetentionPolicy.SOURCE)
      private @interface Region{
  
      }
      @IntDef({STATE_IDLE,STATE_DRAG, STATE_SETTLE})
      @Retention(RetentionPolicy.SOURCE)
      private @interface State{
  
      }
      @IntDef({CENTER,LEFT_TOP,RIGHT_TOP,LEFT_BOTTOM,RIGHT_BOTTOM})
      @Retention(RetentionPolicy.SOURCE)
      private @interface MyGravity{
  
      }
  
  
  
  
      public boolean inScrollMode;
  
  
      private static final int ACTIVE_POINTER_ID_NONE = -1;
      private static final String DESCRIPTION = "Long press";
      private static final String MAIN = "main";
      private static final String SUB = "sub";
      private static final long DEFAULT_DELAYED = 150;
  
      private static final int CHANGE_DURATION = 10;
  
  
      /**
       * 放置主要RecyclerView的容器
       */
      private ViewGroup mMainContainer;
      /**
       * 放置次级RecyclerView的容器
       */
      private ViewGroup mSubContainer;
      /**
       * 被拖动的View
       */
      private View mDragView;
  
  
      private RecyclerView mMainRecyclerView;
      private RecyclerView mSubRecyclerView;
  
      private int mMainSpanCount;
      private int mSubSpanCount;
      private GestureDetectorCompat mMainGestureDetector;
      private GestureDetectorCompat mSubGestureDetector;
  
      private RecyclerView.OnItemTouchListener mMainItemTouchListener;
      private RecyclerView.OnItemTouchListener mSubItemTouchListener;
  
      private MainRecyclerViewCallBack mMainCallBack;
      private SubRecyclerViewCallBack mSubCallBack;
  
      private float mSubRatio;
      private int mMainActivePointerId = ACTIVE_POINTER_ID_NONE;
      private int mSubActivePointerId = ACTIVE_POINTER_ID_NONE;
      private int mAnimationDuration;
  
  
      private int mSelectedStartX;
      private int mSelectedStartY;
      private float mInitialTouchX;
      private float mInitialTouchY;
      private int mStatusBarHeight;
      private float mDx;
      private float mDy;
      private View mSelected;
      private int mSelectedPosition;
      private Dialog mSubDialog;
      private WindowManager mWindowManager;
      private WindowManager.LayoutParams mDragLayoutParams;
      private int mSubContainerWidth;
      private int mSubContainerHeight;
      private List<DragListener> mDragListeners;
      private int[] mMainLocation = new int[2];
      private int[] mSubLocation = new int[2];
      private boolean mMoveListenerEnable = true;
      private boolean mDragViewIsShow = false;
      private boolean mPendingRecover = false;
      @State
      private int mState;
      @Region
      private int mRegion;
      private int mGravity;
      private float mDragScaleX;
      private float mDragScaleY;
      private float mDragInMergeScaleX;
      private float mDragInMergeScaleY;
      /**
       * 储存所有进入了merge状态的position
       */
      private Queue<Integer> mInMergeQueue = new LinkedList<>();
      /**
       * 触发滑动距离
       */
      private int mEdgeWidth;
  
  
      private VelocityTracker mVelocityTracker;
  
      public ClassifyView(Context context) {
          super(context);
          init(context, null, 0);
      }
  
      public ClassifyView(Context context, AttributeSet attrs) {
          super(context, attrs);
          init(context, attrs, 0);
      }
  
      public ClassifyView(Context context, AttributeSet attrs, int defStyleAttr) {
          super(context, attrs, defStyleAttr);
          init(context, attrs, defStyleAttr);
      }
  
  
      @TargetApi(Build.VERSION_CODES.LOLLIPOP)
      public ClassifyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
          super(context, attrs, defStyleAttr, defStyleRes);
          init(context, attrs, defStyleAttr);
      }
  
      /**
       * 初始化容器
       */
      private void init(Context context, AttributeSet attrs, int defStyleAttr) {
          mMainContainer = new FrameLayout(context);
          mSubContainer = new FrameLayout(context);
          mMainContainer.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
          TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ClassifyView, defStyleAttr, R.style.DefaultStyle);
          mSubRatio = a.getFraction(R.styleable.ClassifyView_SubRatio, 1, 1, 0.7f);
          mMainSpanCount = a.getInt(R.styleable.ClassifyView_MainSpanCount, 3);
          mSubSpanCount = a.getInt(R.styleable.ClassifyView_SubSpanCount, 3);
          mAnimationDuration = a.getInt(R.styleable.ClassifyView_AnimationDuration, 200);
          mEdgeWidth = a.getDimensionPixelSize(R.styleable.ClassifyView_EdgeWidth, 15);
          mDragScaleX = a.getFloat(R.styleable.ClassifyView_DragScaleX,1f);
          mDragScaleY = a.getFloat(R.styleable.ClassifyView_DragScaleY,1f);
          mDragInMergeScaleX = a.getFloat(R.styleable.ClassifyView_DragInMergeScaleX,1f);
          mDragInMergeScaleY = a.getFloat(R.styleable.ClassifyView_DragInMergeScaleY,1f);
          mGravity = a.getInt(R.styleable.ClassifyView_DragScalePivotGravity,LEFT_TOP);
          int mainPadding = a.getDimensionPixelSize(R.styleable.ClassifyView_MainPadding,0);
          int mainPaddingLeft = a.getDimensionPixelSize(R.styleable.ClassifyView_MainPaddingLeft,0);
          int mainPaddingTop = a.getDimensionPixelSize(R.styleable.ClassifyView_MainPaddingTop,0);
          int mainPaddingRight = a.getDimensionPixelSize(R.styleable.ClassifyView_MainPaddingRight,0);
          int mainPaddingBottom = a.getDimensionPixelSize(R.styleable.ClassifyView_MainPaddingBottom,0);
          boolean mainClipToPadding = a.getBoolean(R.styleable.ClassifyView_MainClipToPadding,true);
          int subPadding = a.getDimensionPixelSize(R.styleable.ClassifyView_SubPadding,0);
          int subPaddingLeft = a.getDimensionPixelSize(R.styleable.ClassifyView_SubPaddingLeft,0);
          int subPaddingTop = a.getDimensionPixelSize(R.styleable.ClassifyView_SubPaddingTop,0);
          int subPaddingRight = a.getDimensionPixelSize(R.styleable.ClassifyView_SubPaddingRight,0);
          int subPaddingBottom = a.getDimensionPixelSize(R.styleable.ClassifyView_SubPaddingBottom,0);
          boolean subClipToPadding = a.getBoolean(R.styleable.ClassifyView_SubClipToPadding,true);
          a.recycle();
          mMainRecyclerView = getMain(context, attrs);
          if(mainPadding != 0){
              mMainRecyclerView.setPadding(mainPadding,mainPadding,mainPadding,mainPadding);
          }else if(mainPaddingLeft != 0 || mainPaddingTop != 0 || mainPaddingRight != 0 || mainPaddingBottom != 0){
              mMainRecyclerView.setPadding(mainPaddingLeft,mainPaddingTop,mainPaddingRight,mainPaddingBottom);
          }
          mMainRecyclerView.setClipToPadding(mainClipToPadding);
          mSubRecyclerView = getSub(context, attrs);
          if(subPadding > 0){
              mSubRecyclerView.setPadding(subPadding,subPadding,subPadding,subPadding);
          }else if(subPaddingLeft != 0 || subPaddingTop != 0 || subPaddingRight != 0 || subPaddingBottom != 0){
              mSubRecyclerView.setPadding(subPaddingLeft,subPaddingTop,subPaddingRight,subPaddingBottom);
          }
          mSubRecyclerView.setClipToPadding(subClipToPadding);
          mMainContainer.addView(mMainRecyclerView);
          mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
          addViewInLayout(mMainContainer, 0, mMainContainer.getLayoutParams());
          mDragView = new View(context);
          int id = getResources().getIdentifier("status_bar_height", "dimen", "android");
          if (id > 0) {
              mStatusBarHeight = getResources().getDimensionPixelSize(id);
          }
          setUpTouchListener(context);
          mDragListeners = new ArrayList<>();
      }
  
      /**
       * 设置被拖拽的视图缩放的中心点
       * @param gravity
       */
      public void setDragGravity(@MyGravity int gravity){
          mGravity = gravity;
      }
  
      /**
       * 设置被拖拽时的x轴缩放大小(这个缩放大小只影响显示效果)
       * @param dragScaleX
       */
      public void setDragScaleX(float dragScaleX) {
          mDragScaleX = dragScaleX;
      }
      /**
       * 设置被拖拽时的y轴缩放大小(这个缩放大小只影响显示效果)
       * @param dragScaleY
       */
      public void setDragScaleY(float dragScaleY) {
          mDragScaleY = dragScaleY;
      }
  
      /**
       * 设置被拖拽的选项在可合并状态下的x轴缩放大小(这个缩放大小只影响显示效果)
       * @param dragInMergeScaleX
       */
      public void setDragInMergeScaleX(float dragInMergeScaleX) {
          mDragInMergeScaleX = dragInMergeScaleX;
      }
      /**
       * 设置被拖拽的选项在可合并状态下的y轴缩放大小(这个缩放大小只影响显示效果)
       * @param dragInMergeScaleY
       */
      public void setDragInMergeScaleY(float dragInMergeScaleY) {
          mDragInMergeScaleY = dragInMergeScaleY;
      }
  
  
      public void addDragListener(DragListener listener) {
          mDragListeners.add(listener);
      }
  
      public void removeDragListener(DragListener listener) {
          mDragListeners.remove(listener);
      }
  
      public void removeAllDragListener() {
          mDragListeners.clear();
      }
  
      /**
       * 是否开启移动监听
       *
       * @param enable false disable true enable
       */
      public void enableMoveListener(boolean enable) {
          mMoveListenerEnable = enable;
      }
  
  
      @Override
      protected void onDetachedFromWindow() {
          super.onDetachedFromWindow();
          if (mSubDialog != null && mSubDialog.isShowing()) {
              mSubDialog.dismiss();
          }
          if (mDragViewIsShow) {
              mWindowManager.removeViewImmediate(mDragView);
              mDragViewIsShow = false;
          }
      }
  
  
      @Override
      protected void onAttachedToWindow() {
          super.onAttachedToWindow();
          mDragLayoutParams = createDragLayoutParams();
          mDragView.setPivotX(0);
          mDragView.setPivotY(0);
      }
  
  
      /**
       * 生成拖拽view的布局参数
       * @return
       */
      @NonNull
      protected WindowManager.LayoutParams createDragLayoutParams(){
          WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
          layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
          if (Build.VERSION.SDK_INT >= 19)
              layoutParams.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
          layoutParams.format = PixelFormat.TRANSPARENT;
          layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
          layoutParams.token = this.getWindowToken();
          return layoutParams;
      }
  
  
      @Override
      protected void onSizeChanged(int w, int h, int oldw, int oldh) {
          super.onSizeChanged(w, h, oldw, oldh);
          getLocationAndFixHeight(mMainRecyclerView, mMainLocation);
      }
  
      @NonNull
      protected RecyclerView getMain(Context context, AttributeSet parentAttrs) {
          RecyclerView recyclerView = new RecyclerView(context);
          recyclerView.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
          recyclerView.setLayoutManager(new GridLayoutManager(context, mMainSpanCount));
          RecyclerView.ItemAnimator itemAnimator = new ClassifyItemAnimator();
          itemAnimator.setChangeDuration(CHANGE_DURATION);
          recyclerView.setItemAnimator(itemAnimator);
          return recyclerView;
      }
  
      @NonNull
      protected RecyclerView getSub(Context context, AttributeSet parentAttrs) {
          RecyclerView recyclerView = new RecyclerView(context);
          recyclerView.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
          recyclerView.setLayoutManager(new GridLayoutManager(context, mSubSpanCount));
          RecyclerView.ItemAnimator itemAnimator = new ClassifyItemAnimator();
          itemAnimator.setChangeDuration(CHANGE_DURATION);
          recyclerView.setItemAnimator(itemAnimator);
          return recyclerView;
      }
  
  
      public RecyclerView getMainRecyclerView() {
          return mMainRecyclerView;
      }
  
      public RecyclerView getSubRecyclerView() {
          return mSubRecyclerView;
      }
  
      /**
       * 设置主层级与副层级使用一个RecycledViewPool
       *
       * @param viewPool
       */
      public void setShareViewPool(RecyclerView.RecycledViewPool viewPool) {
          getMainRecyclerView().setRecycledViewPool(viewPool);
          getSubRecyclerView().setRecycledViewPool(viewPool);
      }
  
      private View findChildView(RecyclerView recyclerView, MotionEvent event) {
          // first check elevated views, if none, then call RV
          final float x = event.getX();
          final float y = event.getY();
          return recyclerView.findChildViewUnder(x, y);
      }
  
      /**
       * 设置adapter
       *
       * @param mainAdapter
       * @param subAdapter
       */
      public void setAdapter(BaseMainAdapter mainAdapter, BaseSubAdapter subAdapter) {
          mMainRecyclerView.setAdapter(mainAdapter);
          mMainRecyclerView.addOnItemTouchListener(mMainItemTouchListener);
          mMainCallBack = mainAdapter;
          mSubRecyclerView.setAdapter(subAdapter);
          mSubRecyclerView.addOnItemTouchListener(mSubItemTouchListener);
          mSubCallBack = subAdapter;
          mMainRecyclerView.setOnDragListener(new MainDragListener());
      }
  
      /**
       * @param baseSimpleAdapter
       * @see ClassifyView#addDragListener(DragListener)
       */
      public void setAdapter(BaseSimpleAdapter baseSimpleAdapter) {
          setAdapter(baseSimpleAdapter.getMainAdapter(), baseSimpleAdapter.getSubAdapter());
          if (baseSimpleAdapter.isShareViewPool()) {
              setShareViewPool(new RecyclerView.RecycledViewPool());
          }
      }
  
      public RecyclerView.LayoutManager getMainLayoutManager() {
          return mMainRecyclerView.getLayoutManager();
      }
  
      public RecyclerView.LayoutManager getSubLayoutManager() {
          return mSubRecyclerView.getLayoutManager();
      }
  
      /**
       * 初始化 触摸事件监听
       *
       * @param context
       */
      private void setUpTouchListener(Context context) {
          mMainGestureDetector = new GestureDetectorCompat(context, new GestureDetector.SimpleOnGestureListener() {
              @Override
              public boolean onDown(MotionEvent e) {
                  return true;
              }
  
              @Override
              public boolean onSingleTapConfirmed(MotionEvent e) {
                  View pressedView = findChildView(mMainRecyclerView, e);
                  if (pressedView == null) return false;
                  int position = mMainRecyclerView.getChildAdapterPosition(pressedView);
                  List list = mMainCallBack.explodeItem(position, pressedView);
                  if (list == null) {
                      mMainCallBack.onItemClick(mMainRecyclerView,position, pressedView);
                      return true;
                  } else {
                      mSubCallBack.initData(position, list);
                      showSubContainer(position);
                      return true;
                  }
  
              }
  
              @Override
              public void onLongPress(MotionEvent e) {
                  View pressedView = findChildView(mMainRecyclerView, e);
                  if (pressedView == null) return;
                  L.d("Main recycler view on long press: x: %1$s + y: %2$s", e.getX(), e.getY());
                  int position = mMainRecyclerView.getChildAdapterPosition(pressedView);
  
                  int pointerId = MotionEventCompat.getPointerId(e, 0);
                  if (pointerId == mMainActivePointerId) {
                      if (mMainCallBack.canDragOnLongPress(position, pressedView)) {
                          mSelectedPosition = position;
                          mSelectedStartX = pressedView.getLeft();
                          mSelectedStartY = pressedView.getTop();
                          mDx = mDy = 0f;
                          int index = MotionEventCompat.findPointerIndex(e, mMainActivePointerId);
                          mInitialTouchX = MotionEventCompat.getX(e, index);
                          mInitialTouchY = MotionEventCompat.getY(e, index);
                          L.d("handle event on long press:X: %1$s , Y: %2$s ", mInitialTouchX, mInitialTouchY);
                          mRegion = IN_MAIN_REGION;
  //                        inMainRegion = true;
                          mSelected = pressedView;
                          pressedView.startDrag(ClipData.newPlainText(DESCRIPTION, MAIN),
                                  new ClassifyDragShadowBuilder(pressedView), mSelected, 0);
                      }
                  }
              }
          });
          mMainItemTouchListener = new RecyclerView.OnItemTouchListener() {
  
              @Override
              public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
                  mMainGestureDetector.onTouchEvent(e);
                  int action = MotionEventCompat.getActionMasked(e);
                  switch (action) {
                      case MotionEvent.ACTION_DOWN:
                          mMainActivePointerId = MotionEventCompat.getPointerId(e, 0);
                          break;
                      case MotionEvent.ACTION_CANCEL:
                      case MotionEvent.ACTION_UP:
                          mMainActivePointerId = ACTIVE_POINTER_ID_NONE;
                          inMergeState = false;
                          break;
                  }
                  return mSelected != null;
              }
  
              @Override
              public void onTouchEvent(RecyclerView rv, MotionEvent e) {
                  mMainGestureDetector.onTouchEvent(e);
                  int action = MotionEventCompat.getActionMasked(e);
                  switch (action) {
                      case MotionEvent.ACTION_MOVE:
                          L.d("main move");
                          break;
                      case MotionEvent.ACTION_CANCEL:
                      case MotionEvent.ACTION_UP:
                          mMainActivePointerId = ACTIVE_POINTER_ID_NONE;
                          break;
                      case MotionEvent.ACTION_POINTER_UP:
                          int pointerIndex = MotionEventCompat.getActionIndex(e);
                          int pointerId = MotionEventCompat.getPointerId(e, pointerIndex);
                          if (pointerId == mSubActivePointerId) {
                              int newPointerId = pointerIndex == 0 ? 1 : 0;
                              mMainActivePointerId = MotionEventCompat.getPointerId(e, newPointerId);
                          }
                          break;
                  }
              }
  
              @Override
              public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
  
              }
          };
          mSubGestureDetector = new GestureDetectorCompat(context, new GestureDetector.SimpleOnGestureListener() {
              @Override
              public boolean onDown(MotionEvent e) {
                  return true;
              }
  
              @Override
              public boolean onSingleTapConfirmed(MotionEvent e) {
                  View pressedView = findChildView(mSubRecyclerView, e);
                  if (pressedView == null) return false;
                  int position = mSubRecyclerView.getChildAdapterPosition(pressedView);
                  mSubCallBack.onItemClick(mSubRecyclerView,position, pressedView);
                  return true;
              }
  
              @Override
              public void onLongPress(MotionEvent e) {
                  View pressedView = findChildView(mSubRecyclerView, e);
                  if (pressedView == null) return;
                  L.d("Sub recycler view on long press: x: %1$s + y: %2$s", e.getX(), e.getY());
                  int position = mSubRecyclerView.getChildAdapterPosition(pressedView);
                  int pointerId = MotionEventCompat.getPointerId(e, 0);
                  if (pointerId == mSubActivePointerId) {
                      if (mSubCallBack.canDragOnLongPress(position, pressedView)) {
                          if(mState == STATE_DRAG) {
                              L.d("already have item in drag state");
                              return;
                          }
                          mSelectedPosition = position;
                          mSelectedStartX = pressedView.getLeft();
                          mSelectedStartY = pressedView.getTop();
                          mDx = mDy = 0f;
                          int index = MotionEventCompat.findPointerIndex(e, mSubActivePointerId);
                          mInitialTouchX = MotionEventCompat.getX(e, index);
                          mInitialTouchY = MotionEventCompat.getY(e, index);
                          mRegion = IN_SUB_REGION;
                          mSelected = pressedView;
                          restoreDragView();
                          obtainVelocityTracker();
                          float targetX = mInitialTouchX - mSelected.getWidth() / 2 + mSubLocation[0];
                          float targetY = mInitialTouchY - mSelected.getHeight() / 2 + mSubLocation[1];
                          mSubCallBack.setDragPosition(mSelectedPosition,false);
                          mState = STATE_DRAG;
                          mSubCallBack.onDragStart(mSubRecyclerView,mSelectedPosition);
                          for (DragListener listener : mDragListeners) {
                              listener.onDragStart(ClassifyView.this,mSelected,mInitialTouchX, mInitialTouchY, IN_MAIN_REGION);
                          }
                          doStartDragWithAnimation(mSubRecyclerView,mSelected,mSelectedPosition, targetX, targetY, mSubLocation, mSubCallBack);
  
                      }
                  }
              }
          });
          mSubItemTouchListener = new RecyclerView.OnItemTouchListener() {
              @Override
              public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
                  mSubGestureDetector.onTouchEvent(e);
                  int action = MotionEventCompat.getActionMasked(e);
                  switch (action) {
                      case MotionEvent.ACTION_DOWN:
                          mSubActivePointerId = MotionEventCompat.getPointerId(e, 0);
                          mInitialTouchX = e.getX();
                          mInitialTouchY = e.getY();
                          break;
                      case MotionEvent.ACTION_CANCEL:
                      case MotionEvent.ACTION_UP:
                          mSubActivePointerId = ACTIVE_POINTER_ID_NONE;
                          L.d("sub intercept action up or cancel");
                          if(mRegion == UNKNOWN_REGION){
                              mPendingRecover = true;
                          }else {
                              doRecoverAnimation();
                          }
                          break;
                  }
                  return mSelected != null;
              }
  
              @Override
              public void onTouchEvent(RecyclerView rv, MotionEvent e) {
                  if(mSelected == null) return;
                  mSubGestureDetector.onTouchEvent(e);
                  float x = MotionEventCompat.getX(e, mSubActivePointerId);
                  float y = MotionEventCompat.getY(e, mSubActivePointerId);
                  float rawX = e.getRawX();
                  float rawY = e.getRawY();
                  int height = mSelected.getHeight();
                  int width = mSelected.getWidth();
                  int action = MotionEventCompat.getActionMasked(e);
                  switch (action) {
                      case MotionEvent.ACTION_MOVE:
                          if(mRegion == UNKNOWN_REGION) break;
                          if ((mRegion&IN_SUB_REGION) != 0 && (x < 0 || y < 0 || x > mSubContainerWidth || y > mSubContainerHeight)) {
                              //离开次级目录范围
                              if (mSubCallBack.canDragOut(mSelectedPosition)) {
                                  mRegion = IN_MAIN_REGION | SUB_REGION_LEAVE_TYPE;
                                  hideSubContainer();
                                  mSelectedPosition = mMainCallBack.onLeaveSubRegion(mSelectedPosition, mSubCallBack);
                                  mMainCallBack.setDragPosition(mSelectedPosition, true);
                                  mSubCallBack.setDragPosition(-1, true);
                                  mSelectedStartX = mSelectedStartX + mSubLocation[0] - mMainLocation[0];
                                  mSelectedStartY = mSelectedStartY + mSubLocation[1] - mMainLocation[1];
                              }
                              break;
                          }
                          if (mVelocityTracker != null)
                              mVelocityTracker.addMovement(e);
                          mDx = x - mInitialTouchX;
                          mDy = y - mInitialTouchY;
                          mDragView.setX(rawX - width / 2 );
                          mDragView.setY(rawY - height / 2 );
                          moveIfNecessary(mSelected);
                          removeCallbacks(mScrollRunnable);
                          mScrollRunnable.run();
                          if (mMoveListenerEnable) {
                              for (DragListener listener : mDragListeners) {
                                  listener.onMove(ClassifyView.this, x, y, IN_SUB_REGION);
                              }
                          }
                          break;
                      case MotionEvent.ACTION_CANCEL:
                      case MotionEvent.ACTION_UP:
                          mSubActivePointerId = ACTIVE_POINTER_ID_NONE;
                          L.d("sub action up or cancel");
                          if(mRegion == UNKNOWN_REGION){
                              mPendingRecover = true;
                          }
                          if ((mRegion &IN_SUB_REGION) != 0) {
                              doRecoverAnimation();
                              mState = STATE_SETTLE;
                              for (DragListener listener : mDragListeners) {
                                  listener.onDragRelease(ClassifyView.this, x, y, IN_SUB_REGION);
                              }
                          }
                          if ((mRegion & IN_MAIN_REGION)!= 0) {
                              if (inMergeState) {
                                  inMergeState = false;
                                  if (mInMergeQueue.isEmpty()) break;
                                  mLastMergePosition = mInMergeQueue.poll();
                                  if (mSelectedPosition == mLastMergePosition) break;
                                  MergeInfo mergeInfo = mMainCallBack.onPrepareMerge(mMainRecyclerView, mSelectedPosition, mLastMergePosition);
                                  RecyclerView.ViewHolder target = mMainRecyclerView.findViewHolderForAdapterPosition(mLastMergePosition);
                                  if (target == null || mergeInfo == null || target.itemView == mSelected) {
                                      mergeSuccess = false;
                                      break;
                                  }
                                  float scaleX = mergeInfo.scaleX;
                                  float scaleY = mergeInfo.scaleY;
                                  float targetX = mMainLocation[0] + mergeInfo.targetX;
                                  float targetY = mMainLocation[1] + mergeInfo.targetY;
                                  setViewPivot(mDragView,LEFT_TOP);
                                  L.d("targetX:%1$s,targetY:%2$s,scaleX:%3$s,scaleY:%4$s", targetX, targetY, scaleX, scaleY);
                                  mDragView.animate().x(targetX).y(targetY).scaleX(scaleX).scaleY(scaleY).setListener(mMergeAnimListener).setDuration(mAnimationDuration).start();
                                  mergeSuccess = true;
                              } else {
                                  doRecoverAnimation();
                              }
                              mState = STATE_SETTLE;
                              for (DragListener listener : mDragListeners) {
                                  listener.onDragRelease(ClassifyView.this, x, y, IN_MAIN_REGION);
                              }
                          }
                          releaseVelocityTracker();
                          break;
                      case MotionEvent.ACTION_POINTER_UP:
                          int pointerIndex = MotionEventCompat.getActionIndex(e);
                          int pointerId = MotionEventCompat.getPointerId(e, pointerIndex);
                          if (pointerId == mSubActivePointerId) {
                              int newPointerId = pointerIndex == 0 ? 1 : 0;
                              mSubActivePointerId = MotionEventCompat.getPointerId(e, newPointerId);
                          }
                          break;
  
                  }
              }
  
              @Override
              public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
  
              }
          };
      }
  
  
      /**
       * 创建次级目录的弹窗
       * 可以重写该方法修改弹窗的样式 及 动画
       * 注意添加自定义View是无效的
       * 自定义View需要重写{@link #getSubContent()}
       *
       * @return
       */
      protected Dialog createSubDialog() {
          Dialog dialog = new Dialog(getContext(), R.style.ClassifyViewTheme);
          dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
          dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
          WindowManager.LayoutParams layoutParams = dialog.getWindow().getAttributes();
          layoutParams.gravity = Gravity.BOTTOM;
          layoutParams.height = (int) (getHeight() * mSubRatio);
          layoutParams.dimAmount = 0.6f;
          layoutParams.windowAnimations = R.style.DefaultAnimation;
          layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
          layoutParams.flags |= WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
          dialog.setCancelable(true);
          dialog.setCanceledOnTouchOutside(true);
          return dialog;
      }
  
      /**
       * 找到需要添加sub recyclerView 的容器
       *
       * @param group
       * @return
       */
      protected ViewGroup findHaveSubTagContainer(ViewGroup group) {
          String tag = getContext().getString(R.string.sub_container);
          if (tag.equals(group.getTag())) return group;
          for (int i = 0; i < group.getChildCount(); i++) {
              View child = group.getChildAt(i);
              if (child instanceof ViewGroup) {
                  ViewGroup temp = findHaveSubTagContainer((ViewGroup) child);
                  if (temp != null) return temp;
              }
          }
          return null;
      }
  
  
      public void setDebugAble(boolean debugAble) {
          L.setDebugAble(debugAble);
      }
  
      /**
       * 返回的布局 可以定义一个tag作为容器被用来添加次级目录的RecyclerView
       * 你可以修改这部分逻辑通过{@link #findHaveSubTagContainer(ViewGroup)}
       *
       * @return 返回次级目录的跟布局
       */
      protected View getSubContent() {
          return inflate(getContext(), R.layout.sub_content, null);
      }
  
      private Dialog initSubDialog() {
          Dialog dialog = createSubDialog();
          View content = getSubContent();
          if (content instanceof ViewGroup) {
              ViewGroup group = findHaveSubTagContainer((ViewGroup) content);
              if (group == null) {
                  group = (ViewGroup) content;
              }
              group.addView(mSubRecyclerView);
          }
          dialog.setContentView(content);
          WindowManager.LayoutParams params = dialog.getWindow().getAttributes();
          int width = params.width;
          int height = params.height;
          int screenWidth = getResources().getDisplayMetrics().widthPixels;
          int screenHeight = getResources().getDisplayMetrics().widthPixels;
          switch (width) {
              case LayoutParams.MATCH_PARENT:
                  width = screenWidth;
                  break;
              case LayoutParams.WRAP_CONTENT:
                  int childWidth = content.getLayoutParams().width;
                  width = getChildMeasureSpec(MeasureSpec.makeMeasureSpec(screenWidth, MeasureSpec.AT_MOST), 0, childWidth);
                  break;
              default:
                  break;
          }
          switch (height) {
              case LayoutParams.MATCH_PARENT:
                  height = screenHeight;
                  break;
              case LayoutParams.WRAP_CONTENT:
                  int childHeight = content.getLayoutParams().height;
                  height = getChildMeasureSpec(MeasureSpec.makeMeasureSpec(screenHeight, MeasureSpec.AT_MOST), 0, childHeight);
                  break;
              default:
                  break;
          }
          mSubContainerWidth = width;
          mSubContainerHeight = height;
          return dialog;
      }
  
  
      /**
       * 显示次级窗口
       */
      private void showSubContainer(final int position) {
          if (mSubDialog == null) {
              mSubDialog = initSubDialog();
              mSubDialog.setOnShowListener(new DialogInterface.OnShowListener() {
                  @Override
                  public void onShow(DialogInterface dialog) {
                      getLocationAndFixHeight(mSubRecyclerView, mSubLocation);
                  }
              });
              mSubDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
                  @Override
                  public void onDismiss(DialogInterface dialog) {
  
                  }
              });
              mSubDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
                  @Override
                  public void onCancel(DialogInterface dialog) {
                      mSubCallBack.onDialogCancel(mSubDialog,position);
                  }
              });
          }
          mSubDialog.show();
          mSubCallBack.onDialogShow(mSubDialog,position);
      }
  
      private void getLocationAndFixHeight(@NonNull View container, @NonNull int[] holder) {
          container.getLocationOnScreen(holder);
          fixHeight(holder);
      }
  
      private void fixHeight(@NonNull int[] ints) {
          if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
              ints[1] -= mStatusBarHeight;
          }
      }
  
      /**
       * 隐藏次级窗口
       */
      public void hideSubContainer() {
          if (mSubDialog == null) return;
          mSubDialog.hide();
      }
  
      private boolean mergeSuccess = false;
  
      /**
       * 监听在拖拽的View在主层级移动的逻辑处理
       */
      class MainDragListener implements View.OnDragListener {
          @Override
          public boolean onDrag(View v, DragEvent event) {
              if (mSelected == null) return false;
              int action = event.getAction();
              int width = mSelected.getWidth();
              int height = mSelected.getHeight();
              float x = event.getX();
              float y = event.getY();
  //            L.d("Main onDrag X:%1$s,Y:%2$s", x, y);
              float centerX = x - width / 2;
              float centerY = y - height / 2;
              switch (action) {
                  case DragEvent.ACTION_DRAG_STARTED:
                      if ((mRegion & IN_MAIN_REGION) != 0) {
                          if(mState == STATE_DRAG){
                              L.d("already have item in drag state");
                              return false;
                          }
                          restoreDragView();
                          obtainVelocityTracker();
                          //拖动开始之前修正位置
                          getLocationAndFixHeight(mMainRecyclerView, mMainLocation);
                          float targetX = mInitialTouchX - width / 2 + mMainLocation[0];
                          float targetY = mInitialTouchY - height / 2 + mMainLocation[1];
                          mMainCallBack.setDragPosition(mSelectedPosition,false);
                          mState = STATE_DRAG;
                          mMainCallBack.onDragStart(mMainRecyclerView,mSelectedPosition);
                          for (DragListener listener : mDragListeners) {
                              listener.onDragStart(ClassifyView.this,mSelected,mInitialTouchX, mInitialTouchY, IN_MAIN_REGION);
                          }
                          doStartDragWithAnimation(mMainRecyclerView,mSelected,mSelectedPosition, targetX, targetY, mMainLocation,  mMainCallBack);
                      }
                      break;
                  case DragEvent.ACTION_DRAG_LOCATION:
                      if(mRegion == UNKNOWN_REGION) break;
                      mVelocityTracker.addMovement(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
                              MotionEvent.ACTION_MOVE, x, y, 0));
                      mDragView.setX(centerX + mMainLocation[0]);
                      mDragView.setY(centerY + mMainLocation[1]);
                      mDx = x - mInitialTouchX;
                      mDy = y - mInitialTouchY;
                      moveIfNecessary(mSelected);
                      removeCallbacks(mScrollRunnable);
                      mScrollRunnable.run();
                      invalidate();
                      if (mMoveListenerEnable) {
                          for (DragListener listener : mDragListeners) {
                              listener.onMove(ClassifyView.this, x, y, IN_MAIN_REGION);
                          }
                      }
                      break;
                  case DragEvent.ACTION_DRAG_ENDED:
                      L.d("main ended");
                      if (mergeSuccess) {
                          mergeSuccess = false;
                          break;
                      }
                      if ((mRegion & IN_MAIN_REGION) != 0) {
                          doRecoverAnimation();
                      }
                      if(mRegion == UNKNOWN_REGION){
                          mPendingRecover = true;
                      }
                      releaseVelocityTracker();
                      break;
                  case DragEvent.ACTION_DRAG_EXITED:
                      break;
                  case DragEvent.ACTION_DROP:
                      if (inMergeState) {
                          inMergeState = false;
                          if (mInMergeQueue.isEmpty()) break;
                          mLastMergePosition = mInMergeQueue.poll();
                          if (mSelectedPosition == mLastMergePosition) break;
                          MergeInfo mergeInfo = mMainCallBack.onPrepareMerge(mMainRecyclerView, mSelectedPosition, mLastMergePosition);
                          RecyclerView.ViewHolder target = mMainRecyclerView.findViewHolderForAdapterPosition(mLastMergePosition);
                          if (target == null || mergeInfo == null || target.itemView == mSelected) {
                              mergeSuccess = false;
                              break;
                          }
                          float scaleX = mergeInfo.scaleX;
                          float scaleY = mergeInfo.scaleY;
                          float targetX = mMainLocation[0] + mergeInfo.targetX;
                          float targetY = mMainLocation[1] + mergeInfo.targetY;
                          setViewPivot(mDragView,LEFT_TOP);
                          L.d("targetX:%1$s,targetY:%2$s,scaleX:%3$s,scaleY:%4$s", targetX, targetY, scaleX, scaleY);
                          mDragView.animate().x(targetX).y(targetY).scaleX(scaleX).scaleY(scaleY).setListener(mMergeAnimListener).setDuration(mAnimationDuration).start();
                          mergeSuccess = true;
                      }
                      break;
              }
              return true;
          }
      }
  
      private int mLastMergePosition;
      private AnimatorListenerAdapter mMergeAnimListener = new AnimatorListenerAdapter() {
          @Override
          public void onAnimationStart(Animator animation) {
              mMainCallBack.onStartMergeAnimation(mMainRecyclerView, mSelectedPosition, mLastMergePosition, mAnimationDuration);
          }
  
          @Override
          public void onAnimationEnd(Animator animation) {
              mMainCallBack.onMerged(mMainRecyclerView, mSelectedPosition, mLastMergePosition);
              restoreToInitial();
          }
  
          @Override
          public void onAnimationCancel(Animator animation) {
              mMainCallBack.onMerged(mMainRecyclerView, mSelectedPosition, mLastMergePosition);
              restoreToInitial();
          }
      };
  
      protected Drawable getDragDrawable(View view) {
          return new DragDrawable(view);
      }
  
  
  
      private void doStartDragWithAnimation(final RecyclerView recyclerView,final View selected, final int selectedPosition, final float targetX, final float targetY, @NonNull final int[] fixWindowLocation, final BaseCallBack callBack) {
          final int recordRegion = mRegion;//记录当前位置 动画中让位置信息处于位置区域
          selected.post(new Runnable() {
              @Override
              public void run() {
                  mWindowManager.addView(mDragView, mDragLayoutParams);
                  mDragViewIsShow = true;
                  mDragView.setBackgroundDrawable(getDragDrawable(mSelected));
                  mDragView.setX(selected.getLeft() + fixWindowLocation[0]);
                  mDragView.setY(selected.getTop() + fixWindowLocation[1]);
                  callBack.setDragPosition(selectedPosition, true);
                  setViewPivot(mDragView,mGravity);
                  mDragView.animate()
                          .x(targetX).y(targetY)
                          .scaleX(mDragScaleX).scaleY(mDragScaleY)
                          .setDuration(200).setListener(new AnimatorListenerAdapter() {
                      @Override
                      public void onAnimationCancel(Animator animation) {
                          mRegion = recordRegion;
                          if(mPendingRecover){
                              mPendingRecover = false;
                              doRecoverAnimation();
                          }
                      }
  
                      @Override
                      public void onAnimationEnd(Animator animation) {
                          mRegion = recordRegion;
                          mDragView.setScaleX(mDragScaleX);
                          mDragView.setScaleY(mDragScaleY);
                          if(mPendingRecover){
                              mPendingRecover = false;
                              doRecoverAnimation();
                          }else {
                              callBack.onDragAnimationEnd(recyclerView,selectedPosition);
                              for(DragListener listener:mDragListeners){
                                  listener.onDragStartAnimationEnd(ClassifyView.this,selected,mRegion);
                              }
                          }
                      }
                  }).setStartDelay(100).start();
                  mRegion = UNKNOWN_REGION;
              }
          });
      }
  
  
      private void setViewPivot(@NonNull View target,@MyGravity int gravity){
          switch (gravity){
              case CENTER:
                  target.setPivotX(target.getWidth()/2);
                  target.setPivotY(target.getHeight()/2);
                  break;
              case LEFT_TOP:
                  target.setPivotX(0);
                  target.setPivotY(0);
                  break;
              case LEFT_BOTTOM:
                  target.setPivotX(0);
                  target.setPivotY(target.getHeight());
                  break;
              case RIGHT_TOP:
                  target.setPivotX(target.getWidth());
                  target.setPivotY(0);
                  break;
              case RIGHT_BOTTOM:
                  target.setPivotX(target.getWidth());
                  target.setPivotY(target.getHeight());
                  break;
          }
      }
  
  
  
      private float findMaxElevation(RecyclerView recyclerView, View itemView) {
          final int childCount = recyclerView.getChildCount();
          float max = 0;
          for (int i = 0; i < childCount; i++) {
              final View child = recyclerView.getChildAt(i);
              if (child == itemView) {
                  continue;
              }
              final float elevation = ViewCompat.getElevation(child);
              if (elevation > max) {
                  max = elevation;
              }
          }
          return max;
      }
  
      /**
       * 做恢复到之前状态的动画
       */
      private void doRecoverAnimation() {
  
          Animator recoverAnimator = null;
          if ((mRegion & IN_SUB_REGION) != 0) {
              RecyclerView.ViewHolder holder = mSubRecyclerView.findViewHolderForAdapterPosition(mSelectedPosition);
              if (holder == null) {
                  PropertyValuesHolder yOffset = PropertyValuesHolder.ofFloat("y", getHeight() + mSelected.getHeight() + mSubLocation[1]);
                  PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX",1f);
                  PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY",1f);
                  recoverAnimator = ObjectAnimator.ofPropertyValuesHolder(mDragView, yOffset,scaleX,scaleY);
              } else {
                  PropertyValuesHolder xOffset = PropertyValuesHolder.ofFloat("x", mSubLocation[0] + mSubContainer.getLeft() + holder.itemView.getLeft());
                  PropertyValuesHolder yOffset = PropertyValuesHolder.ofFloat("y", mSubLocation[1] + mSubContainer.getTop() + holder.itemView.getTop());
                  PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX",1f);
                  PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY",1f);
                  recoverAnimator = ObjectAnimator.ofPropertyValuesHolder(mDragView, xOffset, yOffset,scaleX,scaleY);
              }
          }
  
          if ((mRegion & IN_MAIN_REGION) != 0) {
              RecyclerView.ViewHolder holder = mMainRecyclerView.findViewHolderForAdapterPosition(mSelectedPosition);
              if (holder == null) {
                  PropertyValuesHolder yOffset = PropertyValuesHolder.ofFloat("y", getHeight() + mSelected.getHeight() + mMainLocation[1]);
                  PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX",1f);
                  PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY",1f);
                  recoverAnimator = ObjectAnimator.ofPropertyValuesHolder(mDragView, yOffset,scaleX,scaleY);
              } else {
                  PropertyValuesHolder xOffset = PropertyValuesHolder.ofFloat("x", holder.itemView.getLeft() + mMainLocation[0]);
                  PropertyValuesHolder yOffset = PropertyValuesHolder.ofFloat("y", holder.itemView.getTop() + mMainLocation[1]);
                  PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX",1f);
                  PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY",1f);
                  recoverAnimator = ObjectAnimator.ofPropertyValuesHolder(mDragView, xOffset, yOffset,scaleX,scaleY);
              }
          }
          if (recoverAnimator == null) return;
          recoverAnimator.setDuration(mAnimationDuration);
          recoverAnimator.setInterpolator(sDragScrollInterpolator);
          recoverAnimator.addListener(mRecoverAnimatorListener);
          recoverAnimator.start();
      }
  
      private AnimatorListenerAdapter mRecoverAnimatorListener = new AnimatorListenerAdapter() {
          @Override
          public void onAnimationEnd(Animator animation) {
              for (DragListener listener : mDragListeners) {
                  listener.onDragEnd(ClassifyView.this, mRegion);
              }
              restoreToInitial();
          }
  
          @Override
          public void onAnimationCancel(Animator animation) {
              restoreToInitial();
          }
      };
  
      private void restoreToInitial() {
          mState = STATE_IDLE;
          mSelected = null;
          mSelectedPosition = -1;
          if ((mRegion & IN_SUB_REGION) != 0) {
              restoreDragViewDelayed(DEFAULT_DELAYED);
              notifyDragCancel(mSubCallBack,mSubRecyclerView);
              mRegion = UNKNOWN_REGION;
          }
          if ((mRegion & IN_MAIN_REGION) != 0) {
              restoreDragViewDelayed(DEFAULT_DELAYED);
              notifyDragCancel(mMainCallBack,mMainRecyclerView);
              mRegion = UNKNOWN_REGION;
          }
      }
  
      private void notifyDragCancel(BaseCallBack callBack, RecyclerView recyclerView) {
          int oldPosition = callBack.getDragPosition();
          if (oldPosition != -1) {
              RecyclerView.ViewHolder holder = recyclerView.findViewHolderForAdapterPosition(oldPosition);
              if (holder != null) {
                  holder.itemView.setVisibility(VISIBLE);
                  callBack.setDragPosition(-1, false);
              } else {
                  callBack.setDragPosition(-1, true);
              }
          } else {
              callBack.setDragPosition(-1, true);
          }
      }
  
  
      private void restoreDragView() {
          L.d("restore drag view:"+mDragView.getLeft()+","+mDragView.getTop()+","+mDragView.getTranslationX()+","+mDragView.getTranslationY());
          mDragView.setScaleX(1f);
          mDragView.setScaleY(1f);
          mDragView.setTranslationX(0f);
          mDragView.setTranslationX(0f);
          if (mDragViewIsShow) {
              mWindowManager.removeViewImmediate(mDragView);
              mDragViewIsShow = false;
          }
      }
  
  
      private void restoreDragViewDelayed(long delayed) {
          postDelayed(new Runnable() {
              @Override
              public void run() {
                  restoreDragView();
              }
          }, delayed);
      }
  
      @Override
      public void setPadding(int left, int top, int right, int bottom) {
          super.setPadding(left, top, right, bottom);
      }
  
      @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
      @Override
      public void setPaddingRelative(int start, int top, int end, int bottom) {
          super.setPaddingRelative(start, top, end, bottom);
      }
  
      @Override
      public void setClipToPadding(boolean clipToPadding) {
          super.setClipToPadding(clipToPadding);
      }
  
      /**
       * If user drags the view to the edge, trigger a scroll if necessary.
       */
      private boolean scrollIfNecessary() {
          RecyclerView recyclerView = null;
          if ((mRegion & IN_MAIN_REGION) != 0) {
              recyclerView = mMainRecyclerView;
          }
          if ((mRegion & IN_SUB_REGION) != 0) {
              recyclerView = mSubRecyclerView;
          }
          if (recyclerView == null) return false;
          final long now = System.currentTimeMillis();
          final long scrollDuration = mDragScrollStartTimeInMs
                  == Long.MIN_VALUE ? 0 : now - mDragScrollStartTimeInMs;
          RecyclerView.LayoutManager lm = recyclerView.getLayoutManager();
  
          int scrollX = 0;
          int scrollY = 0;
          if (lm.canScrollHorizontally()) {
              int curX = (int) (mSelectedStartX + mDx);
              final int leftDiff = curX - mEdgeWidth - recyclerView.getPaddingLeft();
              if (mDx < 0 && leftDiff < 0) {
                  scrollX = leftDiff;
              } else if (mDx > 0) {
                  final int rightDiff =
                          curX + mSelected.getWidth() + mEdgeWidth - (recyclerView.getWidth() - recyclerView.getPaddingRight());
                  if (rightDiff > 0) {
                      scrollX = rightDiff;
                  }
              }
          }
          if (lm.canScrollVertically()) {
              int curY = (int) (mSelectedStartY + mDy);
              final int topDiff = curY - mEdgeWidth - recyclerView.getPaddingTop();
              if (mDy < 0 && topDiff < 0) {
                  scrollY = topDiff;
              } else if (mDy > 0) {
                  final int bottomDiff = curY + mSelected.getHeight() + mEdgeWidth -
                          (recyclerView.getHeight() - recyclerView.getPaddingBottom());
                  if (bottomDiff > 0) {
                      scrollY = bottomDiff;
                  }
              }
          }
          if (scrollX != 0) {
              scrollX = interpolateOutOfBoundsScroll(recyclerView,
                      mSelected.getWidth(), scrollX,
                      recyclerView.getWidth(), scrollDuration);
          }
          if (scrollY != 0) {
              scrollY = interpolateOutOfBoundsScroll(recyclerView,
                      mSelected.getHeight(), scrollY,
                      recyclerView.getHeight(), scrollDuration);
          }
          if (scrollX != 0 || scrollY != 0) {
              if (mDragScrollStartTimeInMs == Long.MIN_VALUE) {
                  mDragScrollStartTimeInMs = now;
              }
              recyclerView.scrollBy(scrollX, scrollY);
              return true;
          }
          mDragScrollStartTimeInMs = Long.MIN_VALUE;
          return false;
      }
  
  
      private int interpolateOutOfBoundsScroll(RecyclerView recyclerView,
                                               int viewSize, int viewSizeOutOfBounds,
                                               int totalSize, long msSinceStartScroll) {
          final int maxScroll = getMaxDragScroll(recyclerView);
          final int absOutOfBounds = Math.abs(viewSizeOutOfBounds);
          final int direction = (int) Math.signum(viewSizeOutOfBounds);
          // might be negative if other direction
          float outOfBoundsRatio = Math.min(1f, 1f * absOutOfBounds / viewSize);
          final int cappedScroll = (int) (direction * maxScroll *
                  sDragViewScrollCapInterpolator.getInterpolation(outOfBoundsRatio));
          final float timeRatio;
          if (msSinceStartScroll > DRAG_SCROLL_ACCELERATION_LIMIT_TIME_MS) {
              timeRatio = 1f;
          } else {
              timeRatio = (float) msSinceStartScroll / DRAG_SCROLL_ACCELERATION_LIMIT_TIME_MS;
          }
          final int value = (int) (cappedScroll * sDragScrollInterpolator
                  .getInterpolation(timeRatio));
          if (value == 0) {
              return viewSizeOutOfBounds > 0 ? 1 : -1;
          }
          return value;
      }
  
      private static final long DRAG_SCROLL_ACCELERATION_LIMIT_TIME_MS = 2000;
      private static final Interpolator sDragViewScrollCapInterpolator = new Interpolator() {
          public float getInterpolation(float t) {
              t -= 1.0f;
              return t * t * t * t * t + 1.0f;
          }
      };
      private static final Interpolator sDragScrollInterpolator = new Interpolator() {
          public float getInterpolation(float t) {
              return t * t * t * t * t;
          }
      };
      private int mCachedMaxScrollSpeed = -1;
  
      private int getMaxDragScroll(RecyclerView recyclerView) {
          if (mCachedMaxScrollSpeed == -1) {
              mCachedMaxScrollSpeed = recyclerView.getResources().getDimensionPixelSize(
                      R.dimen.item_touch_helper_max_drag_scroll_per_frame);
          }
          return mCachedMaxScrollSpeed;
      }
  
      /**
       * When user started to drag scroll. Reset when we don't scroll
       */
      private long mDragScrollStartTimeInMs;
  
  
      /**
       * When user drags a view to the edge, we start scrolling the LayoutManager as long as View
       * is partially out of bounds.
       */
      private final Runnable mScrollRunnable = new Runnable() {
          @Override
          public void run() {
              if (mSelected != null && scrollIfNecessary()) {
                  inScrollMode = true;
                  if (mSelected != null) { //it might be lost during scrolling
                      moveIfNecessary(mSelected);
                  }
                  removeCallbacks(mScrollRunnable);
                  ViewCompat.postOnAnimation(ClassifyView.this, this);
              } else {
                  inScrollMode = false;
              }
          }
      };
      private boolean inMergeState = false;
  
      private void moveIfNecessary(View view) {
          final int x = (int) (mSelectedStartX + mDx);
          final int y = (int) (mSelectedStartY + mDy);
          //如果移动范围在自身范围内
          if (Math.abs(y - view.getTop()) < view.getHeight() * 0.5f
                  && Math.abs(x - view.getLeft())
                  < view.getWidth() * 0.5f) {
              return;
          }
          List<View> swapTargets = findSwapTargets(view);
          if (swapTargets.size() == 0) return;
          View target = chooseTarget(view, swapTargets, x, y);
          if (target == null) return;
          if ((mRegion & IN_SUB_REGION) != 0) {//次级目录下 没有merge形式
              int targetPosition = mSubRecyclerView.getChildAdapterPosition(target);
              int state = mSubCallBack.getCurrentState(mSelected, target, x, y, mVelocityTracker, mSelectedPosition,
                      targetPosition);
              if (state == MOVE_STATE_MOVE) {
                  if (mSubCallBack.onMove(mSelectedPosition, targetPosition)) {
                      mSelectedPosition = targetPosition;
                      RecyclerView.ViewHolder viewHolder = mSubRecyclerView.findViewHolderForAdapterPosition(mSelectedPosition);
                      if (viewHolder != null) mSelected = viewHolder.itemView;
                      mSubCallBack.setDragPosition(targetPosition, true);
                      mSubCallBack.moved(mSelectedPosition, targetPosition);
                  }
              }
          }
          if ((mRegion & IN_MAIN_REGION) != 0) {//在主层级下 有merge状况 以及次级目录拖动到主层级的状况
              int targetPosition = mMainRecyclerView.getChildAdapterPosition(target);
              while (!mInMergeQueue.isEmpty() && mInMergeQueue.peek() != targetPosition) {
                  int i = mInMergeQueue.poll();
                  mMainCallBack.onMergeCancel(mMainRecyclerView, mSelectedPosition, i);
                  inMergeState = false;
              }
              int state = mMainCallBack.getCurrentState(mSelected, target, x, y, mVelocityTracker, mSelectedPosition,
                      targetPosition);
              boolean mergeState = state == MOVE_STATE_MERGE;
              if (!inScrollMode && mergeState ^ inMergeState) {
                  if (mSelectedPosition == targetPosition) return;
                  if (mergeState) {
                      if (mMainCallBack.onMergeStart(mMainRecyclerView, mSelectedPosition, targetPosition)) {
                          inMergeState = true;
                          mInMergeQueue.offer(targetPosition);
                          setViewPivot(mDragView,mGravity);
                          mDragView.animate().scaleX(mDragInMergeScaleX).scaleY(mDragInMergeScaleY).setListener(null).start();
                      }
                  } else {
                      if (!mInMergeQueue.isEmpty() && inMergeState) {
                          while (!mInMergeQueue.isEmpty()) {
                              int i = mInMergeQueue.poll();
                              mMainCallBack.onMergeCancel(mMainRecyclerView, mSelectedPosition, i);
                          }
                          inMergeState = false;
                          mDragView.animate().scaleX(mDragScaleX).scaleY(mDragScaleY).start();
                      }
                  }
              }
              if (state == MOVE_STATE_MOVE) {
                  if (inMergeState && !mInMergeQueue.isEmpty()) {
                      //makeSure trigger mergeCancel
                      while (!mInMergeQueue.isEmpty()) {
                          int i = mInMergeQueue.poll();
                          mMainCallBack.onMergeCancel(mMainRecyclerView, mSelectedPosition, i);
                      }
                      inMergeState = false;
                      mDragView.animate().scaleX(mDragScaleX).scaleY(mDragScaleY).start();
                  }
                  if (mMainCallBack.onMove(mSelectedPosition, targetPosition)) {
                      mSelectedPosition = targetPosition;
                      RecyclerView.ViewHolder viewHolder = mMainRecyclerView.findViewHolderForAdapterPosition(mSelectedPosition);
                      if (viewHolder != null) mSelected = viewHolder.itemView;
                      mMainCallBack.setDragPosition(targetPosition, true);
                      mMainCallBack.moved(mSelectedPosition, targetPosition);
                  }
              }
          }
      }
  
      private List<View> mSwapTargets;
  
      /**
       * 找到当前移动View 有覆盖的view
       *
       * @return
       */
      private List<View> findSwapTargets(View view) {
          if (mSwapTargets == null) {
              mSwapTargets = new ArrayList<>();
          } else {
              mSwapTargets.clear();
          }
          int left = Math.round(mSelectedStartX + mDx);
          int top = Math.round(mSelectedStartY + mDy);
          int right = left + view.getWidth();
          int bottom = top + view.getHeight();
          RecyclerView.LayoutManager lm = null;
          RecyclerView recyclerView = null;
          if ((mRegion & IN_MAIN_REGION) != 0) {
              lm = getMainLayoutManager();
              recyclerView = mMainRecyclerView;
          }
          if ((mRegion & IN_SUB_REGION) != 0) {
              lm = getSubLayoutManager();
              recyclerView = mSubRecyclerView;
          }
          if (lm == null || recyclerView == null) return mSwapTargets;
          int childCount = lm.getChildCount();
          for (int i = 0; i < childCount; i++) {
              View child = lm.getChildAt(i);
              if (child == view) {
                  //本身
                  continue;
              }
              if (child.getBottom() < top || child.getTop() > bottom || child.getLeft() > right || child.getRight() < left) {
                  continue;//没有覆盖到
              }
              int targetPosition = recyclerView.getChildAdapterPosition(child);
              //检验目标位置是否能移动
              if ((mRegion & IN_MAIN_REGION) != 0) {
                  if (!mMainCallBack.canDropOver(mSelectedPosition, targetPosition)) continue;
              }
              if ((mRegion & IN_SUB_REGION) != 0) {
                  if (!mSubCallBack.canDropOver(mSelectedPosition, targetPosition)) continue;
              }
              mSwapTargets.add(child);
          }
          return mSwapTargets;
      }
  
      private void obtainVelocityTracker() {
          if (mVelocityTracker != null) {
              mVelocityTracker.recycle();
          }
          mVelocityTracker = VelocityTracker.obtain();
      }
  
      private void releaseVelocityTracker() {
          if (mVelocityTracker != null) {
              mVelocityTracker.recycle();
              mVelocityTracker = null;
          }
      }
  
      /**
       * 从候选项中找到最有优势的目标
       *
       * @param selected
       * @param swapTargets
       * @param curX
       * @param curY
       * @return
       */
      protected View chooseTarget(View selected, List<View> swapTargets, int curX, int curY) {
          int right = curX + selected.getWidth();
          int bottom = curY + selected.getHeight();
          View winner = null;
          int winnerScore = Integer.MAX_VALUE;
          final int dx = curX - selected.getLeft();
          final int dy = curY - selected.getTop();
          final int targetsSize = swapTargets.size();
          for (int i = 0; i < targetsSize; i++) {
              final View target = swapTargets.get(i);
              final int score = Math.abs(target.getLeft() - curX) + Math.abs(target.getTop() - curY)
                      + Math.abs(target.getBottom() - bottom) + Math.abs(target.getRight() - right);
              if (score < winnerScore) {
                  winnerScore = score;
                  winner = target;
              }
  //            if (dx > 0) {
  //                int diff = target.getRight() - right;
  //                if (diff < 0) {
  //                    final int score = Math.abs(diff);
  //                    if (score > winnerScore) {
  //                        winnerScore = score;
  //                        winner = target;
  //                    }
  //                }
  //            }
  //            if (dx < 0) {
  //                int diff = target.getLeft() - curX;
  //                if (diff > 0) {
  //                    final int score = Math.abs(diff);
  //                    if (score > winnerScore) {
  //                        winnerScore = score;
  //                        winner = target;
  //                    }
  //                }
  //            }
  //            if (dy < 0) {
  //                int diff = target.getTop() - curY;
  //                if (diff > 0) {
  //                    final int score = Math.abs(diff);
  //                    if (score > winnerScore) {
  //                        winnerScore = score;
  //                        winner = target;
  //                    }
  //                }
  //            }
  //
  //            if (dy > 0) {
  //                int diff = target.getBottom() - bottom;
  //                if (diff < 0) {
  //                    final int score = Math.abs(diff);
  //                    if (score > winnerScore) {
  //                        winnerScore = score;
  //                        winner = target;
  //                    }
  //                }
  //            }
          }
          return winner;
      }
  
      /**
       * 获取DragShadowBuilder 用于渲染 被拖动的view
       * 默认使用 {@link ClassifyDragShadowBuilder} 实现 自定义时请重写该方法
       *
       * @param view 被拖动item 的 root view
       * @return
       */
      protected DragShadowBuilder getShadowBuilder(View view) {
          return new ClassifyDragShadowBuilder(view);
      }
  
      private ElevationHelper mElevationHelper = new ElevationHelper();
  
      static class ElevationHelper {
  
          private float findMaxElevation(RecyclerView recyclerView) {
              final int childCount = recyclerView.getChildCount();
              float max = 0;
              for (int i = 0; i < childCount; i++) {
                  final View child = recyclerView.getChildAt(i);
  
                  final float elevation = ViewCompat.getElevation(child);
                  if (elevation > max) {
                      max = elevation;
                  }
              }
              return max;
          }
      }
  
  
      public interface DragListener {
          /**
           * 开始拖拽
           *
           * @param parent parent is ClassifyView
           * @param startX start touch x relative classify view
           * @param startY start touch y relative classify view
           * @param region start drag  region either  main or sub
           */
          void onDragStart(ViewGroup parent,View selectedView, float startX, float startY,@Region int region);
  
          /**
           * star drag animation end
           * @param parent
           * @param selectedView
           * @param region
           */
          void onDragStartAnimationEnd(ViewGroup parent,View selectedView,int region);
  
          /**
           * 拖拽结束(recover animation end)
           */
          void onDragEnd(ViewGroup parent,@Region int region);
  
          /**
           * 释放被拖拽的View
           */
          void onDragRelease(ViewGroup parent, float releaseX, float releaseY,@Region int region);
  
          /**
           * move callback by touch location
           *
           * @param touchX 触摸的X坐标
           * @param touchY 触摸的Y坐标
           */
          void onMove(ViewGroup parent, float touchX, float touchY,@Region int region);
      }
  
  }