美文网首页
自定义View系列(十一)汽车之家滑动折叠列表实现

自定义View系列(十一)汽车之家滑动折叠列表实现

作者: Ayres | 来源:发表于2017-07-12 16:12 被阅读0次

    在看了大神的自定义view之汽车折叠列表之后,发现这个效果还是挺不错的。恰巧在项目中也用的到,就仔细研究一下,不能再老是复制粘贴,不知所以然,下面就来分享一下,自己也做一下总结。希望对自己和别人都有所帮助。

    1.创建VerticalDragListView类继承布局FrameLayout,当然类是可以随便取名

    创建ViewDragHelper 对象同时,创建回调。

     public class VerticalDragListView extends FrameLayout {
                  //可以认为这是系统给我们写好的工具类
     private ViewDragHelper  mDragHelper;
     public VerticalDragListView(Context context) {
        this(context, null);
     }
    
    public VerticalDragListView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    
    public VerticalDragListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mDragHelper=ViewDragHelper.create(this,mDragHelperCallback);
    }
    private ViewDragHelper.Callback mDragHelperCallback=new ViewDragHelper.Callback() {
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            //指定该子view是否可以拖动,就是child
            return true;
        }
    
        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
               //垂直拖动的位置
            return top;
        }
             //列表垂直拖动
         @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            //水平拖动的位置
            return left;
        }
       };
    
    2.只有列表可以拖动,其他控件不能拖动

    重写onFinishInflate()方法 取出列表view

     @Override
      protected void onFinishInflate() {
        super.onFinishInflate();
        //获取子布局个数。只能是2个,否则抛异常
        int childCount=getChildCount();
        if (childCount!=2){
            throw new RuntimeException("VerticalDragListView 只能包含两个子布局");
        }
        //取出第2个子view,可以拖动的
         mDragListView=getChildAt(1);
      }
    

    判断是否是列表view,否则不可以拖动

       @Override
        public boolean tryCaptureView(View child, int pointerId) {
            //指定该子view是否可以拖动,就是child
            //只有列表可以拖动
            return mDragListView==child;
        }
    

    只需要垂直拖动所以不需要重写

       //列表只能垂直拖动
       /* @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            //水平拖动的位置
            return left;
        }*/
    

    判断拖动的距离只能是后面view的高度,先测量后面view的高度,在写逻辑
    测量:

      @Override
      protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (changed){
            //测量view的高度
            View menuView=getChildAt(0);
            mMenuHeight=menuView.getMeasuredHeight();
        }
    }
    

    逻辑:

       @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            //随时垂直拖动移动的位置
            if (top<=0){
                top=0;
            }
            if (top >= mMenuHeight){
                top=mMenuHeight;
            }
            return top;
        }
    
    3. 手指松开的时候两者选择之一,要么打开要么关闭
          @Override
         public void onViewReleased(View releasedChild, float xvel, float yvel) {
    
            if (releasedChild==mDragListView){
    
                if (mDragListView.getTop() >mMenuHeight/2){
                    //滚动到菜单的高度(打开)
                    mDragHelper.settleCapturedViewAt(0,mMenuHeight);
                }else{
                    // 滚动到0的位置(关闭)
                    mDragHelper.settleCapturedViewAt(0,0);
                }
                //重绘
                invalidate();
            }
        }
     @Override
     public void computeScroll() {
    
        if (mDragHelper.continueSettling(true)){
    
            invalidate();
        }
    }
    
    4.解决列表滑动冲突
       private float mDownY;
      @Override
      public boolean onInterceptTouchEvent(MotionEvent ev) {
        if(mMenuIsOpen){
           return true;
        }
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
    
                mDownY=ev.getY();
                //让DragHelper处理一个完整事件
                mDragHelper.processTouchEvent(ev);
    
                break;
            case MotionEvent.ACTION_MOVE:
             float moveY=ev.getY();
                if ((moveY-mDownY)  >0 && !canChildScrollUp()){
    
                    //向下滑动并且滚动到顶部    拦截不让listview处理
                   return true;
                }
    
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }
    
    /**
     * 判断view是否滚动到最顶部,还能不能向上滚
     * @return
     */
    
    public boolean canChildScrollUp() {
        if (android.os.Build.VERSION.SDK_INT < 14) {
            if (mDragListView instanceof AbsListView) {
                final AbsListView absListView = (AbsListView) mDragListView;
                return absListView.getChildCount() > 0
                        && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
                        .getTop() < absListView.getPaddingTop());
            } else {
                return ViewCompat.canScrollVertically(mDragListView, -1) || mDragListView.getScrollY() > 0;
            }
        } else {
            return ViewCompat.canScrollVertically(mDragListView, -1);
        }
    }

    相关文章

      网友评论

          本文标题:自定义View系列(十一)汽车之家滑动折叠列表实现

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