二级滑动侧边栏(自定义DrawerLayout)

背景

最新做的项目需求要实现二级滑动侧边栏菜单,说到侧边栏首先想到的是android的DrawerLayout,但是发现它只有两种状态(打开、关闭),并不能设置打开一半这种效果。
先看看效果:

刚开始的时候,主界面完全看不到侧边栏,这时从侧边栏右滑,会出现一列图标的侧边栏,再从左边缘向右滑动,侧边栏就显示描述 + 图标。 点击菜单栏的三横线, 就可以打开或者关闭侧边栏。(打开侧边栏时会记住上一次的状态, 是只显示图标还是描述 + 图标)。

效果录屏

既然DrawerLayout不能满足需求,而且也并没有找到适合的viewGroup,于是就想着自定义一个viewGroup来满足我的需求. 尝试看了一下DrawerLayout的源码,发现其中一个很重要的东西:ViewDragHelper, 使用该类可以进行View的滑动。 关于ViewDragHelper就不做过多介绍了,参照鸿洋大神的博客:Android ViewDragHelper完全解析 自定义ViewGroup神器

话不多说,首先看下如果构建ViewDragHelper对象,并且需要实现哪些方法。
ViewDragHelper是使用静态方法create来创建实例对象的。
需要传递三个参数

ViewGroup: 当前使用ViewDragHelper的ViewGroup
float: 灵敏度,该值范围是0~1,,越大越灵敏,通常建议就是1
ViewDragHelper.Callback: 回调接口,最主要的实现就是在这里。

代码附上:

mHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {
            /**
             * 该方法的返回值决定哪个子view可以拖动
             * @param child 子view
             * @param pointerId
             * @return true: 代表该child可以被拖动, false: 代表child不可以被拖动
             */
            @Override
            public boolean tryCaptureView(View child, int pointerId) {
                return child == mDrawerView;
            }

            /**
             * 返回一个适当的数值就能实现横向拖动效果,
             * @param child
             * @param left left参数指当前拖动子view应该到达的x坐标 按照常理直接返回该参数就可以了,但是为了让被拖动的view遇到边界就不能再拖动
             *             了,所以就可以对该值进行处理,返回更合理的数值
             * @param dx
             * @return
             */
            @Override
            public int clampViewPositionHorizontal(View child, int left, int dx) {
                int newLeft = Math.max(-child.getWidth(), Math.min(left, 0));
                return newLeft;
            }

            /**
             * 在边缘滑动的时候根据滑动距离移动一个子view
             * @param edgeFlags
             * @param pointerId
             */
            @Override
            public void onEdgeDragStarted(int edgeFlags, int pointerId) {
                mHelper.captureChildView(mDrawerView, pointerId);
            }

            /**
             * 手指释放的时候回调该方法
             * @param releasedChild
             * @param xvel
             * @param yvel
             */
            @Override
            public void onViewReleased(View releasedChild, float xvel, float yvel) {
                final int childWidth = releasedChild.getWidth();
                float offset = (childWidth + releasedChild.getLeft()) * 1.0f / childWidth;
                int width;
                Log.d(TAG, "onViewReleased: xvel : " + xvel + ", offset: " + offset);
                if (offset < PROPORTION * 0.5) {
                    Log.d(TAG, "invisible");
                    width = -childWidth;
                } else if (offset >= PROPORTION * 0.5 && offset <= (1 + PROPORTION) * 0.5) {
                    width = (int) (-childWidth * (1 - PROPORTION));
                    mCurrentWidth = width;
                    Log.d(TAG, "part visible");
                } else {
                    width = 0;
                    mCurrentWidth = width;
                    Log.d(TAG, "visible");
                }
                mHelper.settleCapturedViewAt(
                        width,
                        mDrawerTopMargin);
                invalidate();
            }

            /**
             * changeView在拖动过程中,坐标发生变化时回调该方法,包括手动拖动和view自动滚动
             * @param changedView
             * @param left
             * @param top
             * @param dx
             * @param dy
             */
            @Override
            public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
//                super.onViewPositionChanged(changedView, left, top, dx, dy);
                final int childWidth = changedView.getWidth();
                float offset = (float) (childWidth + left) / childWidth;
                mDrawerOnScreen = offset;
                //offset can callback here
                changedView.setVisibility(offset == 0 ? INVISIBLE : VISIBLE);
                invalidate();
            }

            /**
             * 返回横向拖动的最大距离
             * @param child
             * @return
             */
            @Override
            public int getViewHorizontalDragRange(View child) {
//                return super.getViewHorizontalDragRange(child);
                return child == mDrawerView ? mDrawerView.getWidth() : 0;
            }
        });

代码下载: github

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值