美文网首页
ViewDragHelper使用3

ViewDragHelper使用3

作者: 菜鸟何时起飞 | 来源:发表于2020-04-10 16:19 被阅读0次
20180130214139660.gif
public class SlideUpLayout extends ViewGroup {

    private View mUpView;
    private View mDownView;
    private View mSlideView;
    //private RecyclerView mListView;

    private ViewDragHelper mHelper;

    //上下滑的程度,0表示在upView,1表示在downView
    private float mSlidePercent = 0;

    private boolean mInLayout = false;
    private boolean mFirstLayout = true;


    public SlideUpLayout(Context context, AttributeSet attrs) {
        super(context, attrs);

        mHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {

            @Override
            public int clampViewPositionVertical(View child, int top, int dy) {
                if(child == mUpView){
                    return Math.max(- mUpView.getMeasuredHeight() + mSlideView.getMeasuredHeight(), Math.min(top, 0));
                }else if(child == mDownView){
                    return Math.max(mSlideView.getMeasuredHeight(), Math.min(top, mUpView.getMeasuredHeight()));
                }else if(child == mSlideView){
                    return Math.max(- mSlideView.getMeasuredHeight(), Math.min(top, 0));
                }
                return 0;
            }

            @Override
            public boolean tryCaptureView(View child, int pointerId) {
                return child == mUpView || child == mDownView;
            }

            @Override
            public void onViewReleased(View releasedChild, float xvel, float yvel) {
                if(releasedChild == mUpView){
                    int upViewHeight = mUpView.getMeasuredHeight();
                    int slideViewHeight = mSlideView.getMeasuredHeight();
                    float offset = (upViewHeight + releasedChild.getTop() - slideViewHeight) * 1.0f / (upViewHeight - slideViewHeight);
                    mHelper.settleCapturedViewAt(releasedChild.getLeft(), yvel > 0 || yvel == 0 && offset > 0.5f ? 0 : -upViewHeight + slideViewHeight);
                    invalidate();
                }else if(releasedChild == mDownView){
                    int downViewHeight = mDownView.getMeasuredHeight();
                    int slideViewHeight = mSlideView.getMeasuredHeight();
                    float offset = (releasedChild.getTop() - slideViewHeight) * 1.0f / downViewHeight;
                    mHelper.settleCapturedViewAt(releasedChild.getLeft(), yvel > 0 || yvel == 0 && offset > 0.5f ? mUpView.getMeasuredHeight() : slideViewHeight);
                    invalidate();
                }
            }

            @Override
            public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
                if(changedView == mUpView){
                    mDownView.setTop(top + mUpView.getMeasuredHeight());

                    mSlidePercent = (float) (-top) / mDownView.getMeasuredHeight();
                    if(mSlidePercent > 0.9f){
                        mSlideView.setTop(-mSlideView.getMeasuredHeight() + (int)((mSlidePercent - 0.9f)/(1-0.9) * mSlideView.getMeasuredHeight()));
                    }else{
                        mSlideView.setTop(-mSlideView.getMeasuredHeight());
                    }
                    requestLayout();
                    if(mOnSlideListener != null){
                        mOnSlideListener.onSlide(mSlidePercent);
                    }
                }else if(changedView == mDownView){
                    mUpView.setTop(top - mUpView.getMeasuredHeight());

                    mSlidePercent = (float) (mUpView.getMeasuredHeight() - top) / mDownView.getMeasuredHeight();
                    if(mSlidePercent > 0.9f){
                        mSlideView.setTop(-mSlideView.getMeasuredHeight() + (int)((mSlidePercent - 0.9f)/(1-0.9) * mSlideView.getMeasuredHeight()));
                    }else{
                        mSlideView.setTop(-mSlideView.getMeasuredHeight());
                    }
                    requestLayout();
                    if(mOnSlideListener != null){
                        mOnSlideListener.onSlide(mSlidePercent);
                    }
                }
            }

            @Override
            public int getViewVerticalDragRange(View child) {
                return child == mUpView ? mUpView.getMeasuredHeight() - mSlideView.getMeasuredHeight() :
                        child == mDownView ? mDownView.getMeasuredHeight() :
                                child == mSlideView ? mSlideView.getMeasuredHeight() : 0;
            }
        });
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(widthSize, heightSize);

        mUpView = getChildAt(0);
        mDownView = getChildAt(1);
        mSlideView = getChildAt(2);
        //mListView = mDownView.findViewById(R.id.rv_select_course);


        //up
        MarginLayoutParams lp = (MarginLayoutParams) mUpView.getLayoutParams();
        int widthSpec = MeasureSpec.makeMeasureSpec(
                widthSize - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY);
        int heightSpec = MeasureSpec.makeMeasureSpec(
                heightSize - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY);
        mUpView.measure(widthSpec, heightSpec);

        //slide
        lp = (MarginLayoutParams) mSlideView.getLayoutParams();
        widthSpec = getChildMeasureSpec(widthMeasureSpec,
                lp.leftMargin + lp.rightMargin, lp.width);
        heightSpec = getChildMeasureSpec(heightMeasureSpec,
                lp.topMargin + lp.bottomMargin, lp.height);
        mSlideView.measure(widthSpec, heightSpec);

        //down
        lp = (MarginLayoutParams) mDownView.getLayoutParams();
        widthSpec = MeasureSpec.makeMeasureSpec(
                widthSize - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY);
        heightSpec = MeasureSpec.makeMeasureSpec(
                heightSize - lp.topMargin - lp.bottomMargin - mSlideView.getMeasuredHeight(), MeasureSpec.EXACTLY);
        mDownView.measure(widthSpec, heightSpec);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        mInLayout = true;
        MarginLayoutParams lp = (MarginLayoutParams) mUpView.getLayoutParams();
        int upTop;
        if(mFirstLayout){
            upTop = lp.topMargin;
        }else{
            upTop = mUpView.getTop();
        }
        mUpView.layout(lp.leftMargin, upTop,
                lp.leftMargin + mUpView.getMeasuredWidth(),
                upTop + mUpView.getMeasuredHeight());

        lp = (MarginLayoutParams) mDownView.getLayoutParams();
        int downTop;
        if(mFirstLayout){
            downTop = mUpView.getMeasuredHeight() + lp.topMargin;
        }else{
            downTop = mDownView.getTop();
        }
        mDownView.layout(lp.leftMargin, downTop,
                lp.leftMargin + mDownView.getMeasuredWidth(),
                downTop + mDownView.getMeasuredHeight());

        lp = (MarginLayoutParams) mSlideView.getLayoutParams();
        int slideTop;
        if(mFirstLayout){
            slideTop = - mSlideView.getMeasuredHeight() + lp.topMargin;
        }else{
            slideTop = mSlideView.getTop();
        }
        mSlideView.layout(lp.leftMargin, slideTop,
                lp.leftMargin + mSlideView.getMeasuredWidth(),
                slideTop + mSlideView.getMeasuredHeight());


        mInLayout = false;
        mFirstLayout = false;
    }


    @Override
    public void requestLayout() {
        if(!mInLayout) {
            super.requestLayout();
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mFirstLayout = true;
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        mFirstLayout = true;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //return mHelper.shouldInterceptTouchEvent(ev);

        //方法一:还需要根据坐标是否是mListView的范围,进行控制。该方式更直接,理论上效率会更高
        /*if(isInViewArea(mListView, ev.getRawX(), ev.getRawY()) && mListView.canScrollVertically(-1)){
            //listview可以滚动则交给子view决定
            return false;
        }else{
            //已经滚动到顶部,则交给ViewDragHelper处理
            return mHelper.shouldInterceptTouchEvent(ev);
        }*/

        //方法二:把以上的处理改为更一般的情况,递归获取每个子view进行判断处理
        if(hasViewCanScrollUp(mDownView, ev.getRawX(), ev.getRawY())){
            return false;
        }else{
            return mHelper.shouldInterceptTouchEvent(ev);
        }
    }

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

    @Override
    public void computeScroll() {
        if (mHelper.continueSettling(true)) {
            invalidate();
        }
    }

    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }

    @Override
    protected LayoutParams generateLayoutParams(LayoutParams p) {
        return new MarginLayoutParams(p);
    }

    /**
     * 判断指定点所在的view是否未到顶可以继续上划,如果view为ViewGroup的话还得递归往子view判断进去
     */
    private boolean hasViewCanScrollUp(View view, float x, float y){
        if(view instanceof ViewGroup){
            ViewGroup viewGroup = (ViewGroup) view;
            for(int i=0; i<viewGroup.getChildCount(); i++){
                View child = viewGroup.getChildAt(i);
                if(hasViewCanScrollUp(child, x, y)){
                    return true;
                }
            }
            return isInViewArea(view, x, y) && view.canScrollVertically(-1);
        }else{
            return isInViewArea(view, x, y) && view.canScrollVertically(-1);
        }
    }
    /**
     * 判断坐标是否在view区域内
     */
    private boolean isInViewArea(View view, float x, float y){
        int[] local = new int[2];
        view.getLocationOnScreen(local);
        return x > local[0] && x < local[0]+view.getMeasuredWidth() && y > local[1] && y < local[1]+view.getMeasuredHeight();
    }
    public float getSlidePercent(){
        return mSlidePercent;
    }
    public boolean isSlideUp(){
        return floatCompare(mSlidePercent, 0);
    }
    public boolean isSlideDown(){
        return floatCompare(mSlidePercent, 1);
    }
    public void slideToDown(){
        mHelper.smoothSlideViewTo(mDownView, mDownView.getLeft(), mSlideView.getMeasuredHeight());
        invalidate();
    }
    public void slideToUp(){
        mHelper.smoothSlideViewTo(mUpView, mUpView.getLeft(), 0);
        invalidate();
    }
    private OnSlideListener mOnSlideListener = null;
    /**
     * 外部可设置监听slide的位置回调
     */
    public void setOnSlideListener(OnSlideListener listener) {
        mOnSlideListener = listener;
    }
    public interface OnSlideListener{
        /**
         * slide回调
         * @param percent 取值区间[0, 1],0代表滑到最顶部,1代表滑到最底部
         */
        void onSlide(float percent);
    }
    private boolean floatCompare(float f1, float f2){
        return Math.abs(f1 - f2) < Float.MIN_VALUE;
    }
}

xml

<com.example.glidedemo.dragHelper.SlideUpLayout
      android:id="@+id/slide_layout"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:visibility="visible">

    <FrameLayout
        android:id="@+id/slide_layout_up"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#1f00ffff">
      <TextView
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:gravity="center"
          android:text="up"/>
    </FrameLayout>
    <FrameLayout
        android:id="@+id/slide_layout_down"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#1fffff00">
      <TextView
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:gravity="center"
          android:text="down"/>
      <ListView
          android:id="@+id/slide_layout_down_list"
          android:layout_width="match_parent"
          android:layout_height="match_parent"/>
    </FrameLayout>
    <FrameLayout
        android:id="@+id/slide_layout_slide"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:clickable="true"
        android:background="#1fff00ff">
      <TextView
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:gravity="center"
          android:text="slide"/>
    </FrameLayout>

  </com.example.glidedemo.dragHelper.SlideUpLayout>

相关文章

网友评论

      本文标题:ViewDragHelper使用3

      本文链接:https://www.haomeiwen.com/subject/zpnrmhtx.html