可滑动弹出菜单的自定义Layout,基于ViewGroup

本文介绍了如何创建一个基于ViewGroup的自定义布局,实现可滑动弹出菜单的功能。详细讨论了MeasureSpec的三种模式:精确模式、最大模式和未指定模式,并通过示例展示了它们在组件尺寸设定中的应用。
摘要由CSDN通过智能技术生成
实现原理
通过自定义ViewGroup重写onLayout方法监听 onTouchEvent方法当手指在屏幕滑动时重新对contentView、menuView进行layout。

实现过程
1、重写onMeasure
注意:在OnMeasure方法中调用measureChildren(widthMeasureSpec, heightMeasureSpec),否则子View 尺寸将不被计算.
onMeasure方法中自定义的ViewGroup需要显示的调用 setMeasuredDimension(widthMeasureSpec, heightMeasureSpec)设置容器的宽高
MeasureSpec注解:
{
由一个32位int值表示,前两位表示mode,后两位表示size。

Mode值:

1.精确模式(MeasureSpec.EXACTLY

在这种模式下,尺寸的值是多少,那么这个组件的长或宽就是多少。

2.最大模式(MeasureSpec.AT_MOST

这个也就是父组件,能够给出的最大的空间,当前组件的长或宽最大只能为这么大,当然也可以比这个小。

3.未指定模式(MeasureSpec.UNSPECIFIED

这个就是说,当前组件,可以随便用空间,不受限制。


示例:

    //MeasureSpec.AT_MOST表示此模式下最大允许的数量值
        int heightMode = MeasureSpec.AT_MOST;
        int heightSize = maxHeight;
        //根据mode和size计算出spec值
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
        //设置容器的宽高
        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}


2、onLayout
/**
     * 
     * @param dis 手指移动的距离
     */
    private void layoutChildViewsBySwipeDistance(int dis) {
        log("swipe " + dis);
        int menusWidth = getMenusWidth();
        if (dis > menusWidth) {
            dis = menusWidth;
        }
        if (dis < 0) {
            dis = 0;
        }

        // 将ContentView居中布局,左起始位置是滑动的距离
        contentView.layout(-dis, (getMeasuredHeight() - contentView.getMeasuredHeight()) / 2,
                contentView.getMeasuredWidth() - dis, (getMeasuredHeight() + contentView.getMeasuredHeight()) / 2);

        // 将menuView居中布局,左起始位置是滑动的距离加上ContentView的宽度

        for (int i = 0; i < menuViews.size(); i++) {
            View menuView = menuViews.get(i);
            int leftPosition = 0;
            if (i == 0) {
                leftPosition = contentView.getMeasuredWidth() - dis;
            } else {
                leftPosition = contentView.getMeasuredWidth() - dis;
                for (int j = 0; j < i; j++) {
                    leftPosition += menuViews.get(j).getMeasuredWidth();
                }
            }
            int rightPosition = leftPosition + menuView.getMeasuredWidth();
            menuView.layout(leftPosition, (getMeasuredHeight() - menuView.getMeasuredHeight()) / 2, rightPosition,
                    (getMeasuredHeight() + menuView.getMeasuredHeight()) / 2);

            log(i + " leftPosition = " + leftPosition + " rightPosition = " + rightPosition);
        }
    }

3、对 onTouchEvent的监听
@Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            downX = (int) event.getX();
            if (STATE == 0) {
                if (swipeLayoutContainer != null) {
                    swipeLayoutContainer.closeAllSwipeLayout();
                }
            }
            break;
        case MotionEvent.ACTION_MOVE:
            int dis = (int) (downX - event.getX());
            if (STATE == 1) {
                // 打开状态滑动距离初始值为Menu的Width
                dis += getMenusWidth();
            }
            layoutChildViewsBySwipeDistance(dis);
            if (Math.abs(dis) >= MIN_SWIPE_INTERREPT_DISTANCE) {
                getParent().requestDisallowInterceptTouchEvent(true); //告诉父ViewGroup这个事件不再被中断
            }
            break;
        case MotionEvent.ACTION_UP:
            if ((int) (downX - event.getX()) > getMenusWidth() / 2) {
                openMenu();
            } else {
                closeMenu();
            }
            break;
        }
        return true;
    }

源码见:
https://github.com/mars-ma/AndroidSwipeLayout

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值