com.ouyangzn.view.DragLayout.java Source code

Java tutorial

Introduction

Here is the source code for com.ouyangzn.view.DragLayout.java

Source

/*
 * Copyright (c) 2016.  ouyangzn   <email : ouyangzn@163.com>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.ouyangzn.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
import android.widget.ScrollView;
import com.ouyangzn.R;
import com.ouyangzn.utils.Log;

/**
 * Created by ouyangzn on 2016/10/12.<br/>
 * Description?view??/layout
 */
public class DragLayout extends FrameLayout {

    public final static int DIRECTION_TOP = 0;
    public final static int DIRECTION_BOTTOM = 1;
    public final static int DIRECTION_LEFE = 2;
    public final static int DIRECTION_RIGHT = 3;
    private final static String TAG = DragLayout.class.getSimpleName();
    private Context mContext;
    private int mLayoutWidth;
    private int mLayoutHeight;

    private ViewDragHelper mDragHelper;
    /** ?? */
    private int mRemainDistance;
    /** ??? */
    private int mThresholdDistance;
    /** ??view */
    //private int mDraggedViewId;
    private View mDraggedView;
    /** ??? */
    private int mDirection;
    // X?Y??
    private float mDownX;
    private float mDownY;

    public DragLayout(Context context) {
        this(context, null);
    }

    public DragLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DragLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        mContext = context;

        mDragHelper = ViewDragHelper.create(this, new DragLayout.ViewDragCallback());
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.DragLayout);
        mRemainDistance = ta.getDimensionPixelOffset(R.styleable.DragLayout_remain_distance, 0);
        mThresholdDistance = ta.getDimensionPixelOffset(R.styleable.DragLayout_threshold_distance, 0);
        //mDraggedViewId = ta.getResourceId(R.styleable.DragLayout_dragged_view_id, View.NO_ID);
        mDirection = ta.getInt(R.styleable.DragLayout_direction, DIRECTION_TOP);
        ta.recycle();
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        //if (mDraggedViewId != View.NO_ID) {
        //  mDraggedView = findViewById(mDraggedViewId);
        //} else {
        //  mDraggedView = getChildAt(0);
        //}
        if (getChildCount() != 1) {
            throw new UnsupportedOperationException("DragLayout should has only one direct child");
        }
        mDraggedView = getChildAt(0);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mLayoutWidth = w;
        mLayoutHeight = h;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean helpResult = mDragHelper.shouldInterceptTouchEvent(ev);
        switch (MotionEventCompat.getActionMasked(ev)) {
        case MotionEvent.ACTION_DOWN:
            mDownX = ev.getX();
            mDownY = ev.getY();
            break;
        }
        if (isHorizontalScrollView(mDraggedView)) {
            boolean intercept = false;
            switch (MotionEventCompat.getActionMasked(ev)) {
            case MotionEvent.ACTION_MOVE:
                if (mDirection == DIRECTION_TOP || mDirection == DIRECTION_BOTTOM) {
                    // ?--->support-v4DrawerLayout??
                    intercept = mDragHelper.checkTouchSlop(ViewDragHelper.DIRECTION_VERTICAL, ev.getPointerId(0));
                } else {
                    // ?
                    if (ev.getX() - mDownX > 0) {
                        // view????,
                        if (mDirection == DIRECTION_LEFE && mDraggedView.getRight() == mRemainDistance) {
                            intercept = true;
                        } else if (mDirection == DIRECTION_RIGHT) {
                            // view????view??
                            intercept = !ViewCompat.canScrollHorizontally(mDraggedView, -1);
                        }
                    }
                    // 
                    else {
                        // view?????,
                        if (mDirection == DIRECTION_RIGHT
                                && (mLayoutWidth - mDraggedView.getLeft()) == mRemainDistance) {
                            intercept = true;
                        } else if (mDirection == DIRECTION_LEFE) {
                            // view???view??
                            intercept = !ViewCompat.canScrollHorizontally(mDraggedView, 1);
                        }
                    }
                }
                // ???view
                if (intercept)
                    mDragHelper.captureChildView(mDraggedView, ev.getPointerId(0));
                break;
            }
            return helpResult || intercept;
        }
        if (isVerticalScrollView(mDraggedView)) {
            boolean intercept = false;
            switch (MotionEventCompat.getActionMasked(ev)) {
            case MotionEvent.ACTION_MOVE:
                if (mDirection == DIRECTION_LEFE || mDirection == DIRECTION_RIGHT) {
                    // ?--->support-v4DrawerLayout??
                    intercept = mDragHelper.checkTouchSlop(ViewDragHelper.DIRECTION_HORIZONTAL, ev.getPointerId(0));
                } else {
                    // 
                    if (ev.getY() - mDownY > 0) {
                        if (mDirection == DIRECTION_TOP && mDraggedView.getBottom() == mRemainDistance) {
                            intercept = true;
                        } else if (mDirection == DIRECTION_BOTTOM) {
                            intercept = !ViewCompat.canScrollVertically(mDraggedView, -1);
                        }
                    }
                    // 
                    else {
                        // view????
                        if (mDirection == DIRECTION_BOTTOM
                                && (mLayoutHeight - mDraggedView.getBottom()) == mRemainDistance) {
                            intercept = true;
                        } else if (mDirection == DIRECTION_TOP) {
                            // view???view??
                            intercept = !ViewCompat.canScrollVertically(mDraggedView, 1);
                        }
                    }
                }
                break;
            }
            Log.d(TAG, "----------onInterceptTouchEvent.return = " + (helpResult || intercept));
            // ???view
            if (intercept)
                mDragHelper.captureChildView(mDraggedView, ev.getPointerId(0));
            return helpResult || intercept;
        }
        return helpResult;
    }

    private boolean isHorizontalScrollView(View view) {
        if (view instanceof RecyclerView) {
            RecyclerView recyclerView = (RecyclerView) view;
            RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
            if (layoutManager instanceof LinearLayoutManager) {
                LinearLayoutManager manager = (LinearLayoutManager) layoutManager;
                if (manager.getOrientation() == LinearLayoutManager.HORIZONTAL) {
                    return true;
                }
            }
        }
        return view instanceof HorizontalScrollView || ViewCompat.canScrollHorizontally(view, -1)
                || ViewCompat.canScrollHorizontally(view, 1);
    }

    private boolean isVerticalScrollView(View view) {
        if (view instanceof RecyclerView) {
            RecyclerView recyclerView = (RecyclerView) view;
            RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
            if (layoutManager instanceof LinearLayoutManager) {
                LinearLayoutManager manager = (LinearLayoutManager) layoutManager;
                if (manager.getOrientation() == LinearLayoutManager.VERTICAL) {
                    return true;
                }
            }
        }
        return view instanceof ScrollView || ViewCompat.canScrollVertically(view, -1)
                || ViewCompat.canScrollVertically(view, 1);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mDragHelper.processTouchEvent(event);
        return true;
    }

    @Override
    public void computeScroll() {
        if (mDragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

    class ViewDragCallback extends ViewDragHelper.Callback {

        /** ?null???? */
        private Boolean mIsDragValid;
        private int mDragViewLeft;
        private int mDragViewRight;
        private int mDragViewTop;
        private int mDragViewBottom;
        //private int mDragLayoutWidth;
        //private int mDragLayoutHeight;

        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            Log.d(TAG, "-----------tryCaptureView.pointerId = " + pointerId + " ,child = " + child);
            return child == mDraggedView;
        }

        @Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
            if (changedView != mDraggedView) {
                mIsDragValid = null;
                return;
            }
            //Log.d(TAG, "-----------onViewPositionChanged.left = " + left + " ,top = " + top + " ,dx = " + dx + " ,dy = " + dy);
            // ?
            if (mThresholdDistance == 0) {
                if (mDirection == DIRECTION_TOP || mDirection == DIRECTION_BOTTOM) {
                    mIsDragValid = (Math.abs(top - mDragViewTop) / (float) mDraggedView.getHeight()) > 0.5;
                } else if (mDirection == DIRECTION_LEFE || mDirection == DIRECTION_RIGHT) {
                    mIsDragValid = (Math.abs(left - mDragViewLeft) / (float) mDraggedView.getWidth()) > 0.5;
                }
            } else {
                if (mDirection == DIRECTION_TOP || mDirection == DIRECTION_BOTTOM) {
                    mIsDragValid = Math.abs(top - mDragViewTop) > mThresholdDistance;
                } else if (mDirection == DIRECTION_LEFE || mDirection == DIRECTION_RIGHT) {
                    mIsDragValid = Math.abs(left - mDragViewLeft) > mThresholdDistance;
                }
            }
        }

        @Override
        public void onViewCaptured(View capturedChild, int activePointerId) {
            super.onViewCaptured(capturedChild, activePointerId);
            // ?view??
            mDragViewLeft = capturedChild.getLeft();
            mDragViewRight = capturedChild.getRight();
            mDragViewTop = capturedChild.getTop();
            mDragViewBottom = capturedChild.getBottom();
            //mDragLayoutWidth = DragLayout.this.getWidth();
            //mDragLayoutHeight = DragLayout.this.getHeight();
            Log.d(TAG,
                    "-----------onViewCaptured.mDragViewLeft = " + mDragViewLeft + " ,mDragViewRight = "
                            + mDragViewRight + " ,mDragViewTop = " + mDragViewTop + " ,mDragViewBottom = "
                            + mDragViewBottom);
        }

        @Override
        public void onViewDragStateChanged(int state) {
            Log.d(TAG, "-----------onViewDragStateChanged----------------");
            super.onViewDragStateChanged(state);
        }

        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            //if (releasedChild != mDraggedView) return;
            if (mIsDragValid == null) {
                return;
            }
            Log.d(TAG, "-----------onViewReleased.xvel = " + xvel + " ,yvel = " + yvel);
            // todo ????
            if (mIsDragValid) {
                Log.d(TAG, "-------------------");
                if (mDirection == DIRECTION_TOP) {
                    if (mDragViewTop < 0) {
                        // ???
                        mDragHelper.smoothSlideViewTo(releasedChild, mDragViewLeft, 0);
                    } else {
                        mDragHelper.smoothSlideViewTo(releasedChild, mDragViewLeft,
                                mRemainDistance - releasedChild.getHeight());
                    }
                } else if (mDirection == DIRECTION_BOTTOM) {
                    if (mDragViewBottom > mLayoutHeight) {
                        mDragHelper.smoothSlideViewTo(releasedChild, mDragViewLeft, 0);
                    } else {
                        mDragHelper.smoothSlideViewTo(releasedChild, mDragViewLeft,
                                mDragViewBottom - mRemainDistance);
                    }
                } else if (mDirection == DIRECTION_LEFE) {
                    if (mDragViewLeft < 0) {
                        mDragHelper.smoothSlideViewTo(releasedChild, 0, mDragViewTop);
                    } else {
                        mDragHelper.smoothSlideViewTo(releasedChild, -releasedChild.getWidth() + mRemainDistance,
                                mDragViewTop);
                    }
                } else if (mDirection == DIRECTION_RIGHT) {
                    if (mDragViewRight > mLayoutWidth) {
                        mDragHelper.smoothSlideViewTo(releasedChild, 0, mDragViewTop);
                    } else {
                        mDragHelper.smoothSlideViewTo(releasedChild, releasedChild.getWidth() - mRemainDistance,
                                mDragViewTop);
                    }
                }
            } else {
                // ?
                Log.d(TAG, "-------------------");
                if (mDirection == DIRECTION_TOP) {
                    if (mDragViewTop < 0) {
                        // ???
                        // mDragHelper.smoothSlideViewTo(releasedChild, mDragViewLeft, mDragViewTop);
                        // ?mDragViewTop?????
                        mDragHelper.smoothSlideViewTo(releasedChild, mDragViewLeft,
                                mRemainDistance - releasedChild.getHeight());
                    } else {
                        mDragHelper.smoothSlideViewTo(releasedChild, mDragViewLeft, 0);
                    }
                } else if (mDirection == DIRECTION_BOTTOM) {
                    if (mDragViewBottom > mLayoutHeight) {
                        mDragHelper.smoothSlideViewTo(releasedChild, mDragViewLeft, mDragViewTop);
                    } else {
                        mDragHelper.smoothSlideViewTo(releasedChild, mDragViewLeft, 0);
                    }
                } else if (mDirection == DIRECTION_LEFE) {
                    if (mDragViewLeft < 0) {
                        mDragHelper.smoothSlideViewTo(releasedChild, -releasedChild.getWidth() + mRemainDistance,
                                mDragViewTop);
                    } else {
                        mDragHelper.smoothSlideViewTo(releasedChild, 0, mDragViewTop);
                    }
                } else if (mDirection == DIRECTION_RIGHT) {
                    if (mDragViewRight > mLayoutWidth) {
                        mDragHelper.smoothSlideViewTo(releasedChild, releasedChild.getWidth() - mRemainDistance,
                                mDragViewTop);
                    } else {
                        mDragHelper.smoothSlideViewTo(releasedChild, 0, mDragViewTop);
                    }
                }
            }
            //ScrollerstartScroll
            ViewCompat.postInvalidateOnAnimation(DragLayout.this);
        }

        @Override
        public void onEdgeTouched(int edgeFlags, int pointerId) {
            Log.d(TAG, "-----------onEdgeTouched----------------");
            super.onEdgeTouched(edgeFlags, pointerId);
        }

        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            if (child != mDraggedView || mDirection == DIRECTION_TOP || mDirection == DIRECTION_BOTTOM) {
                return mDragViewLeft;
            }
            //Log.d(TAG, "---------clampViewPositionHorizontal.left = " + left + " ,dx = " + dx);

            if (mDirection == DIRECTION_LEFE) {
                if (left > 0)
                    left = 0;
                if (mDragViewLeft < 0 && left < mDragViewLeft) {
                    left = mDragViewLeft;
                }
            } else {
                if (left < 0)
                    left = 0;
                if (mDragViewRight > mLayoutWidth + mDraggedView.getWidth()) {
                    left = mDragViewLeft;
                }
            }
            return left;
        }

        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            if (child != mDraggedView || mDirection == DIRECTION_LEFE || mDirection == DIRECTION_RIGHT) {
                return mDragViewTop;
            }
            //Log.d(TAG, "---------clampViewPositionVertical.top = " + top + " ,dy = " + dy);
            if (mDirection == DIRECTION_TOP) {
                // ??
                if (top > 0) {
                    top = 0;
                }
                // view????
                if (mDragViewTop < 0 && top < mDragViewTop) {
                    top = mDragViewTop;
                }
            } else {
                // ????
                //if (mScreenHeight - mDragViewTop == mDraggedView.getHeight()) {
                if (top < 0) {
                    top = 0;
                }
                if (mDragViewTop >= mLayoutHeight) {
                    top = mDragViewTop;
                }
            }
            return top;
        }
    }
}