安卓自定义半圆弧形菜单

Posted yhongm

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安卓自定义半圆弧形菜单相关的知识,希望对你有一定的参考价值。

安卓开发自定义ViewGroup实现半圆弧形菜单 ,可实时修改菜单按钮数量,效果如下

使用方法

1.布局文件添加一下属性:

<com.yhongm.arcmenu.ArcMenu
app:main_btn_img="@drawable/main_btn"   //中心按钮的背景
android:id="@+id/arcMenu"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:layout_alignParentBottom="true"></com.yhongm.arcmenu.ArcMenu>

2.java方法:

arcMenu.addChildArcMenu(当前添加子按钮图片资源id,按钮标题,按钮附带的额外信息可以为空)//添加新按钮的方法

arcMenu.layoutChildMenu()//初始化菜单

arcMenu.setShowMenuBtnNum(子按钮显示数量)//设置当前菜单显示子按钮的数量

arcMenu.setOnMenuItemClickListener(this) 设置点击按钮的监听

用到的知识点

  1. 三角函数,通过三角函数计算子按钮的坐标
  2. 自定义ViewGroup,onLayout摆放子按钮的位置

教程

一.onMeasure:

在onMeasure过程中测量子View,防止获取不到子View的宽高

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
        for (int i = 0; i < getChildCount(); i++) 
            View childView = getChildAt(i);
            measureChild(childView,widthMeasureSpec,heightMeasureSpec);
            childView.measure(0, 0);
        
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    

二.onLayout:

1.在onLayout过程中摆放主按钮的位置,以及各个子按钮的位置

 @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) 
        Log.i("ArcMenu", "onLayout,");// yuhongmiao 2017/6/6 下午7:49

        if (changed) 
            layoutMainButton();//中间主按钮的摆放
            layoutChildButtonToggleMenu(300);//子按钮的摆放与子按钮的点击动画处理

        

    

2.主按钮的摆放与主按钮的点击事件

/**
     * 摆放主按钮,设置主按钮的点击事件
     */
    private void layoutMainButton() 

        cButton = getChildAt(0);

        cButton.setOnClickListener(this);

        int l = 0;
        int t = 0;
        int width = cButton.getMeasuredWidth();
        int height = cButton.getMeasuredHeight();

        l = getMeasuredWidth() / 2 - width / 2;
        t = (getMeasuredHeight() - 100) - height / 2;
        cButton.layout(l, t, l + width, t + height);
    

3.各个子按钮的摆放,根据当前设置的显示按钮的数量实时计算每个按钮所占用的角度,通过三角函数计算每个子按钮的横纵坐标摆放

 /**
     * 按钮子按钮的布局与动画
     *
     * @param durationMillis
     */
    private void layoutChildButtonToggleMenu(int durationMillis) 
        setBackgroundColor(Color.parseColor("#66111111"));
        for (int i = 0; i < showMenuBtnNum; i++) //遍历要显示的子按钮

            View childView = getChildAt(i + 1);
            childView.setVisibility(View.VISIBLE);
            int childIndex = i;
            int cWidth = childView.getMeasuredWidth();
            int cHeight = childView.getMeasuredHeight();
            int centerX = getMeasuredWidth() / 2 - cWidth / 2;
            int centerY = (getMeasuredHeight() - 100) - cHeight / 2;
            int cl = 0;
            int ct = 0;
            Double angle = null;
            if (childIndex < showMenuBtnNum) 
                float verticalNum = showMenuBtnNum / 2;
                if (showMenuBtnNum % 2 == 0) 
               // 菜单数量为偶数,中心没有子按钮
                    verticalNum = verticalNum - 0.5f;
                    if (childIndex < verticalNum) 
                    //中心线左侧
                        double currntAngle = (Math.PI / 2 / (verticalNum) * (verticalNum - childIndex));//根据显示数量计算当前所占的角度
                        angle = currntAngle;
                        cl = (int) (mRadius * Math.sin(angle));
                        ct = (int) (mRadius * Math.cos(angle));
                        cl = centerX - cl;
                        ct = centerY - ct;
                        childView.layout(cl, ct, cl + cWidth, ct + cHeight);

                     else if (childIndex > verticalNum) //中心线右侧
                        double currentAngle = (Math.PI / 2 / (verticalNum) * (childIndex - verticalNum));
                        angle = currentAngle;//根据显示数量计算当前所占的角度
                        cl = (int) (mRadius * Math.sin(angle));
                        ct = (int) (mRadius * Math.cos(angle));
                        cl = centerX + cl;
                        ct = centerY - ct;
                        childView.layout(cl, ct, cl + cWidth, ct + cHeight);

                    
                 else 
                // 菜单数量为奇数,中心有子按钮
                    if (childIndex < verticalNum) 
                    //中心线左侧
                        double currntAngle = (Math.PI / 2 / (verticalNum) * (verticalNum - childIndex));//根据显示数量计算当前所占的角度
                        angle = currntAngle;
                        cl = (int) (mRadius * Math.sin(angle));
                        ct = (int) (mRadius * Math.cos(angle));
                        cl = centerX - cl;
                        ct = centerY - ct;
                        childView.layout(cl, ct, cl + cWidth, ct + cHeight);

                     else if (childIndex == verticalNum) //中心线位置
                        double currentAngle = 0;
                        if (verticalNum == 0) 
                            currentAngle = 0;
                         else 
                            currentAngle = ((Math.PI / 2 / (verticalNum)) * (verticalNum - childIndex));
                        
                        angle = currentAngle;
                        cl = (int) (mRadius * Math.sin(angle));
                        ct = (int) (mRadius * Math.cos(angle));
                        cl = centerX - cl;
                        ct = centerY - ct;
                        childView.layout(cl, ct, cl + cWidth, ct + cHeight);

                     else if (childIndex > verticalNum && childIndex < showMenuBtnNum) //中心线右侧
                        double currentAngle = (Math.PI / 2 / (verticalNum) * (childIndex - verticalNum));//根据显示数量计算当前所占的角度
                        angle = currentAngle;
                        cl = (int) (mRadius * Math.sin(angle));
                        ct = (int) (mRadius * Math.cos(angle));
                        cl = centerX + cl;
                        ct = centerY - ct;
                        childView.layout(cl, ct, cl + cWidth, ct + cHeight);

                    
                


            
            int centrePointX = (int) (getChildAt(0).getX() + getChildAt(0).getWidth() / 2 - childView.getWidth() / 2);
            int centrePointY = (int) (getChildAt(0).getY() + getChildAt(0).getHeight() / 2 - childView.getHeight() / 2);
            float viewX = centrePointX - cl;
            float viewY = centrePointY - ct;
            toggleMenuAnim(durationMillis, i, childView, viewX, viewY);

        
        changeMenuStatus();
    

详细代码见Github,点此传送
欢迎大家star,fork

存在很多不足,望大家见谅

以上是关于安卓自定义半圆弧形菜单的主要内容,如果未能解决你的问题,请参考以下文章

如何用滚动制作弧形菜单?

自定义三档半圆开关控件

求教 android半圆弧形的进度条问题

如何在半圆自定义视图上包装内容?

自定义图像视图切割左右边缘半圆形

使用曲线将输入范围弧形拇指连接到滑块