Android圆形旋转菜单开发实例

作者:ywl5320 时间:2023-09-06 11:42:52 

最近帮朋友做了一个动画菜单,感觉有一定的实用价值,就在此给大家分享一下,先看看效果:

Android圆形旋转菜单开发实例

实现思路:

从图中可以看出,这三个(或更多,需要自己再实现)菜单是围绕着中心点旋转的,旋转分为2层,背景旋转和菜单旋转,背景旋转可以直接用旋转动画来实现;菜单的旋转是在以中心点为圆心的圆环上,所以这里用了根据旋转角度求此点在直角坐标系中的坐标点的函数(x = r * cos(rotation* 3.14 / 180) 和y = r * sin(rotation* 3.14 / 180) ),然后根据获取到的点的位置来设置菜单的位置就能实现这种效果。由此可见 数学是很重要的 哈哈~~

有了思路我们就能用代码来实现了:

1、首先自定义View继承相对布局并重写构造函数


/**
* Created by ywl on 2016/8/7.
*/
public class CircleMenuLayout extends RelativeLayout {
 public CircleMenuLayout(Context context) {
   this(context, null);
 }
 public CircleMenuLayout(Context context, AttributeSet attrs) {
   this(context, attrs, 0);
 }
 /**
  * 初始化布局 把旋转背景和中心点添加进去
  * @param context
  * @param attrs
  * @param defStyleAttr
  */
 public CircleMenuLayout(Context context, AttributeSet attrs, int defStyleAttr) {
   super(context, attrs, defStyleAttr);
   this.context = context;
   layoutInflater = LayoutInflater.from(context);
   menuitems = new ArrayList<View>();
   centerview = new View(context);//中心点
   centerview.setId(ID_CENTER_VIEW);
   LayoutParams lp = new LayoutParams(0, 0);
   lp.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
   addView(centerview, lp); //添加中心的 用于旋转定位
   progressBar = new ProgressBar(context);//旋转的背景
   LayoutParams lp2 = new LayoutParams(dip2px(context, 90), dip2px(context, 90));
   lp2.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
   addView(progressBar, lp2);
   progressBar.setIndeterminateDrawable(context.getResources().getDrawable(R.mipmap.icon_circle_menu));
 }
}

构造函数中添加中心定位点和旋转背景图片,并设置合适的大小。

2、根据传入的图片数组和菜单名字数组,生成菜单原始位置效果。


/**
  * 菜单的数量 和 半径 名字 和图片 这里只为3个菜单做了适配
  * @param size
  * @param center_distance
  */
 public void initMenuItem(int size, int center_distance, String[] titles, int[] imgs)
 {
   radus = 360f / size;
   int width = dip2px(context, 50); //菜单宽度
   int height = dip2px(context, 50);//菜单高度
   for(int i = 0; i < size; i++) //循环添加布局
   {
     int top = 0;
     int left = 0;
     top = -(int)(Math.sin(radus * i * 3.1415f / 180) * center_distance); //r  *  cos(ao  *  3.14  /180  )
     left = -(int)(Math.cos(radus * i * 3.1415f / 180) * center_distance); //计算位置点
     LayoutParams lp = new LayoutParams(dip2px(context, 50), dip2px(context, 50));
     View view = layoutInflater.inflate(R.layout.item_circle_menu, this, false);
     view.setTag(i);
     TextView tvname = (TextView) view.findViewById(R.id.tv_name);
     ImageView ivimg = (ImageView) view.findViewById(R.id.img);
     tvname.setText(titles[i]);
     ivimg.setImageResource(imgs[i]);
     view.setOnClickListener(new OnClickListener() {
       @Override
       public void onClick(View v) {//根据点击的区域 旋转菜单
         if(!isrun) {
           tag = (int) v.getTag();
           currentPosition = tag;
           if(tag == 0)
           {
             finishdus = -360;
           }
           else if(tag == 1)
           {
             finishdus = -120;
           }
           else if(tag == 2)
           {
             finishdus = -240;
           }
           LayoutParams lp = (LayoutParams) v.getLayoutParams();
           int l = lp.leftMargin;
           int t = lp.topMargin;
           if (t > -dip2px(context, 5) && l > -dip2px(context, 5)) {
             oldradus = 120f;
             isright = false;
           } else if (t > -dip2px(context, 5) && l < -dip2px(context, 5)) {
             oldradus = 120f;
             isright = true;
           } else if (t < -dip2px(context, 5)) {
             oldradus = 0f;
           }
           sub = 0;
           circleMenu(8, dip2px(context, 45), oldradus, isright);
         }
       }
     });
     lp.addRule(RelativeLayout.BELOW, centerview.getId());
     lp.addRule(RelativeLayout.RIGHT_OF, centerview.getId());
     lp.setMargins(-width / 2 + top, -height / 2 + left, 0, 0);
     addView(view, lp);
     menuitems.add(view);
   }
   handler.postDelayed(runnable, 0);
 }

根据菜单的数量循环计算每个菜单的位置,然后在相应的位置添加相应的菜单就可以实现菜单的初始化了。这里为每个菜单添加了点击事件,但是只适配了3个菜单的情况,至于其他数量的菜单,可以自己来改或者写一个通用的方法来计算点击位置。

3、背景旋转动画:


/**
 * 根据度数来旋转菜单 菜单中心都在一个圆上面 采用圆周运动来旋转
 * @param offserradius
 * @param center_distance
 * @param d
 * @param right
 */
 public void circleMenu(float offserradius, int center_distance, float d, boolean right)
 {
 if(oldradus != 0)
 {
   progressBar.clearAnimation();
   if(isright)
   {
     mRotateUpAnim = new RotateAnimation(bgdus, bgdus + 120,
         Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
         0.5f);
     bgdus += 120;
   }
   else
   {
     mRotateUpAnim = new RotateAnimation(bgdus, bgdus - 120,
         Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
         0.5f);
     bgdus -= 120;
   }
   lir = new LinearInterpolator();
   mRotateUpAnim.setDuration(350);
   mRotateUpAnim.setFillAfter(true);
   mRotateUpAnim.setInterpolator(lir);
//    mRotateUpAnim.setRepeatCount(Animation.INFINITE);
   progressBar.startAnimation(mRotateUpAnim);
 }
   circleMenuItem(offserradius, center_distance, d, right);
 }

这个比较简单,就是根据旋转的角度,启用旋转动画。

4、旋转菜单:


/**
  * 菜单旋转
  * @param offserradius
  * @param center_distance
  * @param d
  * @param right
  */
 public void circleMenuItem(float offserradius, int center_distance, float d, boolean right)
 {
   sub += offserradius;
   if(sub > d)
   {
     if(onMenuItemSelectedListener != null)
     {
       onMenuItemSelectedListener.onMenuItemOnclick(tag);
     }
     isrun = false;
     return;
   }
   if(right) {
     offsetradus -= offserradius;
   }
   else
   {
     offsetradus += offserradius;
   }
   int size = menuitems.size();
   int width = dip2px(context, 50);
   int height = dip2px(context, 50);
   for(int i = 0; i < size; i++)
   {
     if(Math.abs(sub - d) <= 8)
     {
       offsetradus = finishdus;
     }
     LayoutParams lp = (LayoutParams) menuitems.get(i).getLayoutParams();
     float ds = radus * i + offsetradus;
     int top = -(int)(Math.sin(ds * 3.1415f / 180) * center_distance); //r  *  cos(ao  *  3.14  /180  )
     int left = -(int)(Math.cos(ds * 3.1415f / 180) * center_distance);
     lp.setMargins(-width / 2 + top, -height / 2 + left, 0, 0);
     menuitems.get(i).requestLayout();
   }
   if(sub <= d) {
     isrun = true;
     offsetradus = offsetradus % 360;
     handler.postDelayed(runnable, 5);
   }
   else
   {
     if(onMenuItemSelectedListener != null)
     {
       onMenuItemSelectedListener.onMenuItemOnclick(tag);
     }
     isrun = false;
   }
 }

这里旋转是根据初始化时每个菜单所在的位置来求的旋转角度,然后启动handler来动递加或递减角度来求响应的位置,就实现了动画效果。

5、手动设置菜单项(有局限,没有通用性):


/**
  * 设置旋转到哪个菜单项
  * @param tag
  */
 public void setCurrentTag(int tag)
 {
   if(currentPosition == tag)
   {
     return;
   }
   if(tag == 0)
   {
     finishdus = -360;
   }
   else if(tag == 1)
   {
     finishdus = -120;
   }
   else if(tag == 2)
   {
     finishdus = -240;
   }
   if(currentPosition == 0) //当前是0
   {
     if(tag == 1)
     {
       oldradus = 120f;
       isright = true;
     }
     else if(tag == 2)
     {
       oldradus = 120f;
       isright = false;
     }
   }
   else if(currentPosition == 1)
   {
     if(tag == 2)
     {
       oldradus = 120f;
       isright = true;
     }
     else if(tag == 0)
     {
       oldradus = 120f;
       isright = false;
     }
   }
   else if(currentPosition == 2)
   {
     if(tag == 0)
     {
       oldradus = 120f;
       isright = true;
     }
     else if(tag == 1)
     {
       oldradus = 120f;
       isright = false;
     }
   }
   currentPosition = tag;
   this.tag = tag;
   sub = 0;
   circleMenu(8, dip2px(context, 45), oldradus, isright);
 }

这样就可以实现旋转效果了。

6、调用方法:

(1)布局文件:


<com.ywl5320.circlemenu.CircleMenuLayout
   android:id="@+id/cml_menu"
   android:layout_width="150dp"
   android:layout_height="150dp"
   android:layout_centerHorizontal="true"
   android:layout_alignParentBottom="true"
   android:layout_marginBottom="92dp"/>

(2)菜单布局文件:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical"  
 android:layout_width="100dp"
 android:layout_height="100dp"
 android:padding="5dp"
 android:gravity="center">
 <ImageView
   android:id="@+id/img"
   android:layout_width="25dp"
   android:layout_height="25dp"
   android:scaleType="fitXY"/>
 <TextView
   android:id="@+id/tv_name"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="菜单项"
   android:textSize="9sp"
   android:gravity="center"
   android:textColor="#ffffff"/>
</LinearLayout>

(3)Activity中调用


<span style="white-space:pre">  </span>cmlmenu = (CircleMenuLayout) findViewById(R.id.cml_menu);
   btn = (Button) findViewById(R.id.btn);
   cmlmenu.initDatas(titles, imgs);
   cmlmenu.setOnMenuItemSelectedListener(new CircleMenuLayout.OnMenuItemSelectedListener() {
     @Override
     public void onMenuItemOnclick(int code) {
       if(code == 0)//
       {
         Toast.makeText(MainActivity.this, "支付宝", Toast.LENGTH_SHORT).show();
       }
       else if(code == 1)
       {
         Toast.makeText(MainActivity.this, "银联", Toast.LENGTH_SHORT).show();
       }
       else if(code == 2)
       {
         Toast.makeText(MainActivity.this, "微信", Toast.LENGTH_SHORT).show();
       }
     }
   });

OK,就完成了三个菜单旋转效果(注:这里仅仅是为了3个菜单而设计的,其他个数的自己还需要精简或更改一些代码,相信自己改出来的会更有收获的~~)。

以上所述是小编给大家介绍的Android圆形旋转菜单开发实例网站的支持!

来源:http://blog.csdn.net/ywl5320/article/details/52449392

标签:android,旋转,菜单
0
投稿

猜你喜欢

  • 使用fileupload组件实现文件上传功能

    2023-05-04 02:48:06
  • MAC下如何设置JDK环境变量

    2023-12-20 16:05:24
  • Java数据结构之顺序表的实现

    2023-06-22 00:47:26
  • MyBatis使用雪花ID的实现

    2023-06-09 16:26:23
  • Java实现的模糊匹配某文件夹下的文件并删除功能示例

    2022-02-28 13:51:46
  • C++ 关于MFC多线程编程的注意事项

    2023-02-17 22:34:44
  • C++ 双向循环链表类模版实例详解

    2022-10-29 18:04:49
  • 基于java集合中的一些易混淆的知识点(详解)

    2023-08-29 03:06:26
  • Java cookie和session会话技术介绍

    2021-12-30 06:51:22
  • Android自定义ListView实现下拉刷新上拉加载更多

    2021-08-20 21:17:04
  • Spring自动装配Bean实现过程详解

    2023-10-31 18:35:21
  • C# Winform多屏幕多显示器编程技巧实例

    2021-09-19 16:49:09
  • 浅谈Java的两种多线程实现方式

    2022-08-17 09:42:37
  • 浅析Mybatis 在CS程序中的应用

    2023-06-24 08:44:15
  • springboot实现基于aop的切面日志

    2022-09-09 11:53:11
  • Android Studio 新建项目通过git上传到码云图文教程详解

    2021-08-09 12:12:05
  • Windows下Flutter+Idea环境搭建及配置

    2022-01-22 18:12:13
  • JAVA 生成随机数并根据后台概率灵活生成的实例代码

    2023-12-05 11:00:48
  • C#导入导出EXCEL文件的代码实例

    2022-04-21 07:15:15
  • Android为Tiny4412设备驱动在proc目录下添加一个可读版本信息的文件

    2022-09-24 05:37:20
  • asp之家 软件编程 m.aspxhome.com