美文网首页
View-仿汽车之家-折叠列表的实现

View-仿汽车之家-折叠列表的实现

作者: cao苗子 | 来源:发表于2019-08-05 14:46 被阅读0次

1.先看效果图:

仿汽车之家折叠列表.gif

2.效果分析

2.1.后面的布局不能拖动
2.2.前面的只能垂直拖动

//1.拖动我们的子view
   private ViewDragHelper.Callback mViewDragHelperCallback = new ViewDragHelper.Callback() {
       @Override
       public boolean tryCaptureView(@NonNull View child, int pointerId) {
           //在这里可以指定子 view 是否可以拖动
           //只能是前面的布局才能滑动
           return mDragListView == child;
       }

       @Override
       public int clampViewPositionVertical(@NonNull View child, int top, int dy) {
           //垂直拖动的滑动距离
           Log.d("TAG","top="+top);
           if(top < 0){
               top = 0;
           }

           if(top > mInnerViewheight){
               top = mInnerViewheight;
           }

           return top;
       }

   };

2.3.垂直拖动的范围只能是后面菜单的高度

@Override
  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
      super.onLayout(changed, left, top, right, bottom);
      if(changed){
          mInnerViewheight = getChildAt(0).getMeasuredHeight();
      }
  }

2.4.松开的时候只能打开或是关闭

  /**
         * 拖动松开的时候
         * @param releasedChild
         * @param xvel
         * @param yvel
         */
        @Override
        public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild, xvel, yvel);
            if(releasedChild == mDragContentView) {
                if (mDragContentView.getTop() > mInnerViewHeight / 2) {
                    //滚动到菜单的高度
                    mViewDragHelper.settleCapturedViewAt(0, mInnerViewHeight);
                } else {
                    //恢复
                    mViewDragHelper.settleCapturedViewAt(0, 0);
                }
                invalidate();
            }
        }
//相应滚动
 @Override
    public void computeScroll() {
        super.computeScroll();
        if(mViewDragHelper.continueSettling(true)){
            invalidate();
        }
    }

3.内容页是滑动控件

比如是 ListView 解决滑动冲突
判断是否是ListView

 /*
    判断是否还能不能向上滚动 源码 来自于 SwipeRefreshLayout
     */
    private boolean canChildScrollUp() {
        if (mDragContentView instanceof ListView) {
            return canScrollList((ListView) mDragContentView, -1);
        }
        return false;
    }
    private boolean canScrollList(ListView listView, int direction) {
        if (Build.VERSION.SDK_INT >= 19) {
            // Call the framework version directly
            return listView.canScrollList(direction);
        } else {
            // provide backport on earlier versions
            final int childCount = listView.getChildCount();
            if (childCount == 0) {
                return false;
            }

            final int firstPosition = listView.getFirstVisiblePosition();
            if (direction > 0) {
                final int lastBottom = listView.getChildAt(childCount - 1).getBottom();
                final int lastPosition = firstPosition + childCount;
                return lastPosition < listView.getCount()
                        || (lastBottom > listView.getHeight() - listView.getListPaddingBottom());
            } else {
                final int firstTop = listView.getChildAt(0).getTop();
                return firstPosition > 0 || firstTop < listView.getListPaddingTop();
            }
        }
    }

如果是ListView,在判断是否滑动到顶部的时候 需要做拦截事件

  case MotionEvent.ACTION_MOVE:
                float moveY = ev.getY();
                Log.d("TAG","moveY="+moveY+"  mDownY="+mDownY);
                if(moveY - mDownY > 0 && !canChildScrollUp()){
                    //向下滑动 && 滚动到顶部 拦截 不让ListView做处理
                    return true;
                }
                break;

其他滑动冲突说明:

//现象:如果contentView是ListView listView可以滑动 但是 拖动效果没有了 所以要解决事件冲突
//because ACTION_DOWN was not received for this pointer before ACTION_MOVE
//出现以上的原因:
//流程分析:VerticalDragListLayout.onInterceptTouchEvent.DOWN -> ListView.OnTouch()->
//VerticalDragListLayout.onInterceptTouchEvent.MOVE - > VerticalDragListLayout.OnTouchEvent.MOVE
//看到上面的流程可以看到 ListView的DOWN事件被拦截了 因为重写了 onTouchEvent return true了

完整的事件拦截代码:

@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //如果 菜单 是打开的 则全部拦截
        if(mInnerViewIsOpen){
            return true;
        }
        //向下滑动的时候 不要给ListView做处理
        //父类拦截子类
        //requestDisallowInterceptTouchEvent 请求父类不要拦截子类的事件 也就是不需要修改mGroupFlags的值
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                mDownY = ev.getY();
                //所以我们要在这里 给DragHelper一个完整的事件
                mViewDragHelper.processTouchEvent(ev);
                break;
            case MotionEvent.ACTION_MOVE:
                float moveY = ev.getY();
                Log.d("TAG","moveY="+moveY+"  mDownY="+mDownY);
                if(moveY - mDownY > 0 && !canChildScrollUp()){
                    //向下滑动 && 滚动到顶部 拦截 不让ListView做处理
                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }

到此已经完毕

4.源码地址

https://github.com/panshimu/VerticalDragListLayout

有问题随时留言
QQ 362976241
谢谢!

相关文章

网友评论

      本文标题:View-仿汽车之家-折叠列表的实现

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