com.ouyangzn.view.TopDragLayout.java Source code

Java tutorial

Introduction

Here is the source code for com.ouyangzn.view.TopDragLayout.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/9/12.<br/>
 * Description?view??/layout
 */
public class TopDragLayout extends FrameLayout {

    private final static String TAG = TopDragLayout.class.getSimpleName();

    private ViewDragHelper mDragHelper;
    /** ??? */
    private int mRemainHeight;
    /** ?? */
    private int mThresholdHeight;
    /** ??view */
    private int mDraggedViewId;
    private View mDraggedView;
    private float downY;

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

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

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

    private void init(Context context, AttributeSet attrs) {
        mDragHelper = ViewDragHelper.create(this, new ViewDragCallback());
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TopDragLayout);
        mRemainHeight = ta.getDimensionPixelOffset(R.styleable.TopDragLayout_remain_height, 0);
        mThresholdHeight = ta.getDimensionPixelOffset(R.styleable.TopDragLayout_threshold_height, 0);
        mDraggedViewId = ta.getResourceId(R.styleable.TopDragLayout_dragged_view_id, View.NO_ID);
        ta.recycle();
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        if (mDraggedViewId != View.NO_ID) {
            mDraggedView = findViewById(mDraggedViewId);
        } else {
            mDraggedView = getChildAt(0);
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean helpResult = mDragHelper.shouldInterceptTouchEvent(ev);
        if (isHorizontalScrollView(mDraggedView)) {
            boolean intercept = false;
            switch (MotionEventCompat.getActionMasked(ev)) {
            case MotionEvent.ACTION_MOVE:
                // ?--->support-v4DrawerLayout??
                intercept = mDragHelper.checkTouchSlop(ViewDragHelper.DIRECTION_VERTICAL);
                // ???view
                if (intercept)
                    mDragHelper.captureChildView(mDraggedView, ev.getPointerId(0));
                break;
            }
            return helpResult || intercept;
        }
        if (isVerticalScrollView(mDraggedView)) {
            // ?View???
            if (mDraggedView.getBottom() == mRemainHeight) {
                mDragHelper.captureChildView(mDraggedView, ev.getPointerId(0));
                return true;
            }
            boolean intercept = false;
            switch (MotionEventCompat.getActionMasked(ev)) {
            case MotionEvent.ACTION_DOWN:
                downY = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                // 
                if (ev.getY() - downY > 0) {
                    intercept = !ViewCompat.canScrollVertically(mDraggedView, -1);
                    Log.d(TAG, "----------intercept = " + intercept);
                } else {
                    intercept = !ViewCompat.canScrollVertically(mDraggedView, 1);
                    Log.d(TAG, "----------intercept = " + intercept);
                }
                break;
            }
            Log.d(TAG, "----------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 mDragViewTop;
        private int mDragViewBottom;

        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            Log.d(TAG, "-----------tryCaptureView----------------");
            Log.d(TAG, "----------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----------------");
            Log.d(TAG, "----------left = " + left + " ,top = " + top + " ,dx = " + dx + " ,dy = " + dy
                    + " ,changedView = " + changedView);
            // ?
            if (mThresholdHeight == 0) {
                mIsDragValid = (Math.abs(top - mDragViewTop) / (float) changedView.getHeight()) > 0.5;
            } else {
                mIsDragValid = Math.abs(top - mDragViewTop) > mThresholdHeight;
            }
        }

        @Override
        public void onViewCaptured(View capturedChild, int activePointerId) {
            super.onViewCaptured(capturedChild, activePointerId);
            // ?view??
            mDragViewLeft = capturedChild.getLeft();
            mDragViewTop = capturedChild.getTop();
            mDragViewBottom = capturedChild.getBottom();
            Log.d(TAG, "-----------onViewCaptured.mDragViewLeft = " + mDragViewLeft + " ,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----------------");
            Log.d(TAG, "----------xvel = " + xvel + " ,yvel = " + yvel + " ,releasedChild = " + releasedChild);
            if (mIsDragValid) {
                Log.d(TAG, "-------------------");
                if (mDragViewTop < 0) {
                    // ???
                    mDragHelper.smoothSlideViewTo(releasedChild, mDragViewLeft, 0);
                } else {
                    mDragHelper.smoothSlideViewTo(releasedChild, mDragViewLeft,
                            mRemainHeight - releasedChild.getHeight());
                }
                //ScrollerstartScroll
                ViewCompat.postInvalidateOnAnimation(TopDragLayout.this);
            } else {
                // ?
                Log.d(TAG, "-------------------");
                if (mDragViewTop < 0) {
                    // ???
                    mDragHelper.smoothSlideViewTo(releasedChild, mDragViewLeft,
                            mRemainHeight - releasedChild.getHeight());
                } else {
                    mDragHelper.smoothSlideViewTo(releasedChild, mDragViewLeft, 0);
                }
                ViewCompat.postInvalidateOnAnimation(TopDragLayout.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) {
            Log.d(TAG,
                    "---------clampViewPositionHorizontal.left = " + left + " ,dx = " + dx + " ,child = " + child);
            // ???
            return mDragViewLeft;
        }

        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            if (child != mDraggedView)
                return child.getTop();
            Log.d(TAG, "---------clampViewPositionVertical.top = " + top + " ,dy = " + dy + " ,child = " + child);
            // ??
            if (top > 0) {
                top = 0;
            }
            // view????
            if (mDragViewTop < 0 && top < mDragViewTop) {
                top = mDragViewTop;
            }
            return top;
        }
    }
}