自定义可展开的菜单 MenuButtonLayout

啥都先不说,先上效果图
刚开始
刚一开始加载到的界面
点击展开
按钮展开
随便选择一个,ViewPager切换
ViewPager切换

核心思路是运用属性动画,对该菜单中的每个按钮实行移动。 由于是属性动画,所以不用担心只是动了图片而无法真正的移动这个问题。

由于菜单中要加入许多的按钮,所以我选择的是自定义ViewGroup. 既然是ViewGroup,那我们就需要重写 onMeasure() onLayout() 这两个方法

onMeasure()中,不多说,遍历出子View并且测量他们,通过子View的宽高来确定该ViewGroup的宽高,和弹出后每个按钮之间的间距

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        childMaxWidth = 0;
        mMaxHeight = 0;
        for (int i = 0; i < mChildCount; i++) {
            View child = getChildAt(i);
            mMaxHeight = Math.max(mMaxHeight, child.getMeasuredHeight());
            childMaxWidth = Math.max(childMaxWidth, child.getMeasuredHeight());
        }
        //弹出后每个按钮之间的距离
        expandPadding = childMaxWidth + padding;
        //弹出后菜单的总宽
        mMaxnWidth = expandPadding * (mChildCount - 1) + childMaxWidth;
        setMeasuredDimension(mMaxnWidth, mMaxHeight);
    }

测量完之后是onLayout(),布置各个子View的位置,这里考虑到奇数偶数的时候中心点不一样

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int left = 0;
        int top = 0;
        int right = 0;
        int bottom = 0;
        //奇数个子View
        if (mChildCount % 2 != 0) {
            left = (mMaxnWidth / 2) - (childMaxWidth / 2);
            top = 0;
            right = (mMaxnWidth / 2) + (childMaxWidth / 2);
            bottom = mMaxHeight;

            for (int i = 0; i < mChildCount; i++) {
                View child = getChildAt(i);
                child.layout(left, top, right, bottom);
            }
        } else {
        //偶数个的情况下
            left = (mMaxnWidth / 2) + padding / 2;
            top = 0;
            right = left + childMaxWidth;
            bottom = mMaxHeight;

            for (int i = 0; i < mChildCount; i++) {
                View child = getChildAt(i);
                child.layout(left, top, right, bottom);
            }
        }
    }

最后是动画效果

//展开
    private void open() {
        ObjectAnimator[] oas = new ObjectAnimator[mChildCount];
        //整除获取中间值
        int middle = mChildCount / 2;
        for (int i = 0; i < mChildCount; i++) {
            View child = myViews.get(i);
            int times = i - middle;
            //根据不同位置位移不同距离
            ObjectAnimator oa = ObjectAnimator.ofFloat(child, "translationX", expandPadding * times);
            oas[i] = oa;
        }
        AnimatorSet set = new AnimatorSet();
        set.setInterpolator(new BounceInterpolator());
        set.setDuration(500);
        set.playTogether(oas);
        set.start();
        isExpanded = true;
    }
//收起
    private void close() {
        ObjectAnimator[] oas = new ObjectAnimator[mChildCount];
        for (int i = 0; i < mChildCount; i++) {
            View child = getChildAt(i);
            //属性动画,X轴上位移为0,也就是回归原来的位置
            ObjectAnimator oa = ObjectAnimator.ofFloat(child, "translationX", 0);
            oas[i] = oa;
        }

        AnimatorSet set = new AnimatorSet();
        set.setDuration(500);
        set.playTogether(oas);
        set.start();

        isExpanded = false;
        if (listener != null) {
            //点击接口回调
            listener.changeBaseView(currentItem);
        }
    }

最后放上整体代码

public class MenuButtonLayout extends ViewGroup implements View.OnClickListener{
    private boolean isExpanded = false;// 菜单是否打开
    private int mMaxnWidth;// 总宽度
    private int mMaxHeight;// 总高度
    private int mChildCount = 0;
    private int expandPadding = 200;
    private int padding = 20;


    private List<View> myViews;
    private int childMaxWidth;

    private int currentItem;

    public MenuButtonLayout(Context context) {
        this(context, null);
    }

    public MenuButtonLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MenuButtonLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setClickable(true);
        myViews = new ArrayList<View>();
    }

    /**
     * 设置收起后显示的那个view
     *
     * @param index
     */
    public void setCurrentView(int index) {
        View mBaseView = myViews.get(index);
        bringChildToFront(mBaseView);
        invalidate();
    }


    /**
     * 加入View
     *
     * @param view
     */
    public void addItemView(View view) {
        view.setTag(mChildCount);
        view.setOnClickListener(this);
        addView(view, mChildCount);
        myViews.add(view);
        mChildCount++;
    }

    /**
     * 测量
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        childMaxWidth = 0;
        mMaxHeight = 0;
        for (int i = 0; i < mChildCount; i++) {
            View child = getChildAt(i);
            mMaxHeight = Math.max(mMaxHeight, child.getMeasuredHeight());
            childMaxWidth = Math.max(childMaxWidth, child.getMeasuredHeight());
        }
        expandPadding = childMaxWidth + padding;
        mMaxnWidth = expandPadding * (mChildCount - 1) + childMaxWidth;
        setMeasuredDimension(mMaxnWidth, mMaxHeight);
    }

    /**
     * 布局
     *
     * @param changed
     * @param l
     * @param t
     * @param r
     * @param b
     */
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int left = 0;
        int top = 0;
        int right = 0;
        int bottom = 0;

        if (mChildCount % 2 != 0) {
            left = (mMaxnWidth / 2) - (childMaxWidth / 2);
            top = 0;
            right = (mMaxnWidth / 2) + (childMaxWidth / 2);
            bottom = mMaxHeight;

            for (int i = 0; i < mChildCount; i++) {
                View child = getChildAt(i);
                child.layout(left, top, right, bottom);
            }
        } else {
            left = (mMaxnWidth / 2) + padding / 2;
            top = 0;
            right = left + childMaxWidth;
            bottom = mMaxHeight;

            for (int i = 0; i < mChildCount; i++) {
                View child = getChildAt(i);
                child.layout(left, top, right, bottom);
            }
        }
    }

    /**
     * 展开或者收起
     */
    private void doMenuAction() {
        if (isExpanded) {
            close();
        } else {
            open();
        }
    }

    private void open() {
        ObjectAnimator[] oas = new ObjectAnimator[mChildCount];
        //整除获取中间值
        int middle = mChildCount / 2;
        for (int i = 0; i < mChildCount; i++) {
            View child = myViews.get(i);
            int times = i - middle;
            ObjectAnimator oa = ObjectAnimator.ofFloat(child, "translationX", expandPadding * times);
            oas[i] = oa;
        }
        AnimatorSet set = new AnimatorSet();
        set.setInterpolator(new BounceInterpolator());
        set.setDuration(500);
        set.playTogether(oas);
        set.start();
        isExpanded = true;
    }

    private void close() {
        ObjectAnimator[] oas = new ObjectAnimator[mChildCount];
        for (int i = 0; i < mChildCount; i++) {
            View child = getChildAt(i);
            ObjectAnimator oa = ObjectAnimator.ofFloat(child, "translationX", 0);
            oas[i] = oa;
        }

        AnimatorSet set = new AnimatorSet();
        set.setDuration(500);
        set.playTogether(oas);
        set.start();

        isExpanded = false;
        if (listener != null) {
            listener.changeBaseView(currentItem);
        }
    }

    @Override
    public void onClick(View v) {
        int index = (int) v.getTag();
        currentItem = index;
        setCurrentView(index);
        doMenuAction();
    }


    /**
     * 设置按钮间距
     */
    public void setPadding(int padding) {
        this.padding = padding;
    }

    private onItemClickListener listener;
    public interface onItemClickListener {
        /**
         * 按钮改变回调
         *
         * @param index 改变按钮的序号
         */
        void changeBaseView(int index);
    }

    public void setOnItemClickListenr(onItemClickListener listenr) {
        this.listener = listenr;
    }

}

在Activity中的使用
先在布局文件中声明。(这里我就不写了)
然后设置好一些你要展开的按钮

for (int i = 0; i < 5; i++) {
            TextView imageView = new TextView(this);
            int index = i + 1;
            imageView.setText(index + "");
            imageView.setGravity(Gravity.CENTER);
            imageView.setBackground(getDrawable(R.drawable.already_bid_bade));
            menuButtonLayout.addItemView(imageView);

        }
        //设置显示在最上面的按钮
        menuButtonLayout.setCurrentView(0);

给你的菜单加上监听回调

 menuButtonLayout.setOnItemClickListenr(new MenuButtonLayout.onItemClickListener() {
            @Override
            public void changeBaseView(int index) {
                Toast.makeText(MainActivity.this, "第" + (index + 1) + "个按钮被点击了", Toast.LENGTH_SHORT).show();
                //切换ViewPager
                mVp.setCurrentItem(index);
            }
        });

本人水平并不是很高,可能还有许多不足的地方,希望大家可以指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值