content: package yifeiyuan.practice.practicedemos.viewdrager;
  
  import android.content.Context;
  import android.support.v4.widget.ViewDragHelper;
  import android.util.AttributeSet;
  import android.util.Log;
  import android.view.MotionEvent;
  import android.view.View;
  import android.widget.LinearLayout;
  
  /**
   * Created by alanchen on 15/7/14.
   *
   * onFinishInflate
   * onAttachedToWindow
   * onMeasure
   * onLayout
   * onMeasure
   * onLayout
   *
   *
   * 一般流程:             return
   * tryCaptureView        true
   * onViewCaptured
   * 一直move:clampViewPositionVertical/clampViewPositionHorizontal  left/top值
   * up:onViewReleased
   */
  public class DragerView extends LinearLayout {
  
      public static final String TAG = DragerView.class.getSimpleName();
  
      private ViewDragHelper mDragHelper;
  
      public DragerView(Context context) {
          this(context, null);
      }
  
      public DragerView(Context context, AttributeSet attrs) {
          this(context, attrs, 0);
      }
  
      public DragerView(Context context, AttributeSet attrs, int defStyleAttr) {
          super(context, attrs, defStyleAttr);
          init();
      }
  
  
      private int originLeft;
      private int originTop;
      private void init() {
  
          mDragHelper = ViewDragHelper.create(this, 1f, new ViewDragHelper.Callback() {
  
              /**
               *
               * @param child  用户想要拖动的view
               * @param pointerId
               * @return true 代表可以拖动
               */
              @Override
              public boolean tryCaptureView(View child, int pointerId) {
                  Log.d(TAG, "tryCaptureView() called with " + "child = [" + child + "], pointerId = [" + pointerId + "]");
                  return child == mNormal || child == mAutoBack||child == mClickableView;
              }
  
              /**
               * 当某个view 被captured 后会被调用
               * @param capturedChild
               * @param activePointerId
               */
              @Override
              public void onViewCaptured(View capturedChild, int activePointerId) {
                  Log.d(TAG, "onViewCaptured() called with " + "capturedChild = [" + capturedChild + "], activePointerId = [" + activePointerId + "]");
                  super.onViewCaptured(capturedChild, activePointerId);
              }
  
              /**
               * 水平固定?
               * 限制子view
               *
               * @param child 移动的view
               * @param left  即将移动到的位置 以此确定x轴的位置
               * @param dx    差值 从5 ~8 那么dx就是3
               * @return
               */
              @Override
              public int clampViewPositionHorizontal(View child, int left, int dx) {
                  Log.d(TAG, "clampViewPositionHorizontal() called with " + "left = [" + left + "], dx = [" + dx + "]");
                  int leftbound = getPaddingLeft();
                  int rightbound = mWidth - getPaddingRight() - child.getWidth();
  //                return Math.max(left,0);//感觉像是整个坐标系 在 整个屏幕上
                  return Math.min(Math.max(leftbound, left), rightbound);
              }
  
              @Override
              public int clampViewPositionVertical(View child, int top, int dy) {
                  Log.d(TAG, "clampViewPositionVertical() called with " + "top = [" + top + "], dy = [" + dy + "]");
                  return top;
              }
  
              @Override
              public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
                  Log.d(TAG, "onViewPositionChanged() called with " + "changedView = [" + changedView + "], left = [" + left + "], top = [" + top + "], dx = [" + dx + "], dy = [" + dy + "]");
                  super.onViewPositionChanged(changedView, left, top, dx, dy);
              }
  
              @Override
              public void onViewReleased(View releasedChild, float xvel, float yvel) {
                  Log.d(TAG, "onViewReleased() called with " + "releasedChild = [" + releasedChild + "], xvel = [" + xvel + "], yvel = [" + yvel + "]");
                  super.onViewReleased(releasedChild, xvel, yvel);
                  if (releasedChild == mAutoBack) {
                      //Notice 其实 就是scroller.startScroll 所以记得要invalidate 还要重写 computeScroll
                      mDragHelper.settleCapturedViewAt(originLeft, originTop);
                      invalidate();
                  }
  
              }
  
              /**
               * 拖动状态改变
               * @see ViewDragHelper#STATE_IDLE     0        停止
               * STATE_DRAGGING                     1        正在被拖动
               * STATE_SETTLING                     2        自动移动?
               * @param state
               */
              @Override
              public void onViewDragStateChanged(int state) {
                  Log.d(TAG, "onViewDragStateChanged() called with " + "state = [" + state + "]");
                  super.onViewDragStateChanged(state);
              }
  
              /**
               * 当被订阅的边界被touch 时 触发
               * @param edgeFlags
               * @param pointerId
               */
              @Override
              public void onEdgeTouched(int edgeFlags, int pointerId) {
                  Log.d(TAG, "onEdgeTouched() called with " + "edgeFlags = [" + edgeFlags + "], pointerId = [" + pointerId + "]");
                  super.onEdgeTouched(edgeFlags, pointerId);
  
                  //Notice captureChildView 强制capture 无视try
                  if (ViewDragHelper.EDGE_LEFT == edgeFlags) {
                      mDragHelper.captureChildView(mEdgeLeft, pointerId);
                  } else if (ViewDragHelper.EDGE_RIGHT == edgeFlags) {
                      mDragHelper.captureChildView(mEdgeRight, pointerId);
                  }
              }
  
  
              @Override
              public boolean onEdgeLock(int edgeFlags) {
                  Log.d(TAG, "onEdgeLock() called with " + "edgeFlags = [" + edgeFlags + "]");
                  return super.onEdgeLock(edgeFlags);
              }
  
              @Override
              public void onEdgeDragStarted(int edgeFlags, int pointerId) {
                  Log.d(TAG, "onEdgeDragStarted() called with " + "edgeFlags = [" + edgeFlags + "], pointerId = [" + pointerId + "]");
                  super.onEdgeDragStarted(edgeFlags, pointerId);
              }
  
              @Override
              public int getOrderedChildIndex(int index) {
                  Log.d(TAG, "getOrderedChildIndex() called with " + "index = [" + index + "]");
                  return super.getOrderedChildIndex(index);
              }
  
  
              /**
               *  Notice  当想要拖动的子view 有点击事件的时候需要重写
               *  Notice  想在水平上能拖动 getViewHorizontalDragRange 需要return 一个>0的数
               *  Notice  同理 垂直:  getViewVerticalDragRange   也需要return 一个>0的数
               * @param child
               * @return
               */
              @Override
              public int getViewHorizontalDragRange(View child) {
                  Log.d(TAG, "getViewHorizontalDragRange() called with " + "child = [" + child + "]");
  //                return super.getViewHorizontalDragRange(child);
                  return 1;
              }
  
              /**
               * @param child
               * @return
               */
              @Override
              public int getViewVerticalDragRange(View child) {
                  Log.d(TAG, "getViewVerticalDragRange() called with " + "child = [" + child + "]");
  //                return super.getViewVerticalDragRange(child);
                  return 1;
              }
          });
  
          /**
           * 订阅边界触发
           * 当用户触摸边界 会触发 onEdgeTouched
           */
          mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT | ViewDragHelper.EDGE_RIGHT);
  
      }
  
  
      @Override
      public void computeScroll() {
          super.computeScroll();
  
          if (mDragHelper.continueSettling(true)) {
              invalidate();
          }
      }
  
      @Override
      public boolean onInterceptTouchEvent(MotionEvent ev) {
          Log.d(TAG, "onInterceptTouchEvent() called with " + "ev = [" + ev + "]");
        return mDragHelper.shouldInterceptTouchEvent(ev);
  //        mDragHelper.shouldInterceptTouchEvent(ev);
  //        return true;
      }
  
      @Override
      public boolean onTouchEvent(MotionEvent event) {
          Log.d(TAG, "onTouchEvent() called with " + "event = [" + event + "]");
          mDragHelper.processTouchEvent(event);
  //        return super.onTouchEvent(event);
          return true;
      }
  
      private View mNormal;
      private View mAutoBack;
      private View mEdgeLeft;
      private View mEdgeRight;
      private View mClickableView;
  
      @Override
      protected void onFinishInflate() {
          super.onFinishInflate();
          Log.d(TAG, "onFinishInflate ");
          mNormal = getChildAt(0);
          mAutoBack = getChildAt(1);
          mEdgeLeft = getChildAt(2);
          mEdgeRight = getChildAt(3);
          mClickableView = getChildAt(4);
      }
  
      private int mHeight;
      private int mWidth;
      @Override
      protected void onLayout(boolean changed, int l, int t, int r, int b) {
          super.onLayout(changed, l, t, r, b);
          Log.d(TAG, "onLayout ");
          mWidth = getWidth();
          mHeight = getHeight();
          originLeft = mAutoBack.getLeft();
          originTop = mAutoBack.getTop();
      }
  
      @Override
      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
          super.onMeasure(widthMeasureSpec, heightMeasureSpec);
          Log.d(TAG, "onMeasure ");
      }
  
      @Override
      protected void onAttachedToWindow() {
          super.onAttachedToWindow();
          Log.d(TAG, "onAttachedToWindow ");
      }
  
      @Override
      protected void onDetachedFromWindow() {
          super.onDetachedFromWindow();
          Log.d(TAG, "onDetachedFromWindow ");
      }
  }