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圆形旋转菜单开发实例,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • 详解Android事件的分发、拦截和执行

    在平常的开发中,我们经常会遇到点击,滑动之类的事件.有时候不同的view之间也存在各种滑动冲突.比如布局的内外两层都能滑动的话,那么就会出现冲突了.这个时候我们就需要了解Android的事件分发机制. Android的触摸事件分发过程由三个很重要的方法来共同完成:dispatchTouchEvent.onInterceptTouchEvent.onTouchEvent.我先将这三个方法大体的介绍一下. •public boolean dispatchTouchEvent(MotionEvent

  • Android中获取设备的各种信息总结

    一.屏幕分辨率 Display display = getWindowManager().getDefaultDisplay(); Point size = new Point(); display.getSize(size); int width = size.x; int height = size.y; 或者: DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getM

  • android 获取本机的IP地址和mac物理地址的实现方法

    获取本机IP地址 public String getLocalIpAddress() { WifiManager wifiManager = (WifiManager) getSystemService(android.content.Context.WIFI_SERVICE); WifiInfo wifiInfo = wifiManager.getConnectionInfo(); int ipAddress = wifiInfo.getIpAddress(); try { return In

  • android实现获取有线和无线Ip地址的方法

    本文实例讲述了android实现获取有线和无线Ip地址的方法.分享给大家供大家参考.具体如下: 做android的开发时,遇到了获取有线ip地址的问题.不多说 上代码! for (Enumeration<NetworkInterface> en = NetworkInterface .getNetworkInterfaces(); en.hasMoreElements();) { NetworkInterface intf = en.nextElement(); if (intf.getNam

  • 分享一个Android设置圆形图片的特别方法

    Cardview配合ImageView显示圆形图效果图: 刚在看自定义View的知识点时,突然想起来,如果CardView宽高相等,CardView设置圆角的半径为宽高的一半时,不就是一个圆形嘛?! 1.布局文件 <android.support.v7.widget.CardView android:id="@+id/cv_img_activity" android:layout_width="200dp" android:layout_height=&quo

  • Android手机获取IP地址的两种方法

    1.使用WIFI 首先设置用户权限 复制代码 代码如下: <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>  <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>  <

  • Ubuntu Android源码以及内核下载与编译

    本教程是基于Ubuntu下Android6.0.1源码以及内核的下载和编译,记录一下,以后也就不用自己去找资料,一遍一遍的尝试了.可以翻墙的,英语好的,直接去AndroidSource. 系统环境:Ubuntu14.04LTS Android版本:6.0.1 重要网址 清华大学镜像 AndroidSource 下载前的准备 安装OpenJdk sudo add-apt-repository ppa:openjdk-r/ppa sudo apt-get update sudo apt-get in

  • Android 图片缩放实例详解

    本文实现Android中的图片的缩放效果 首先设计布局: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_par

  • Android圆形旋转菜单开发实例

    最近帮朋友做了一个动画菜单,感觉有一定的实用价值,就在此给大家分享一下,先看看效果: 实现思路: 从图中可以看出,这三个(或更多,需要自己再实现)菜单是围绕着中心点旋转的,旋转分为2层,背景旋转和菜单旋转,背景旋转可以直接用旋转动画来实现:菜单的旋转是在以中心点为圆心的圆环上,所以这里用了根据旋转角度求此点在直角坐标系中的坐标点的函数(x = r * cos(rotation* 3.14 / 180) 和y = r * sin(rotation* 3.14 / 180) ),然后根据获取到的点的

  • Android USB转串口通信开发实例详解

     Android USB转串口通信开发实例详解 好久没有写文章了,年前公司新开了一个项目,是和usb转串口通信相关的,需求是用安卓平板通过usb转接后与好几个外设进行通信,一直忙到最近,才慢慢闲下来,趁着这个周末不忙,记录下usb转串口通信开发的基本流程. 我们开发使用的是usb主机模式,即:安卓平板作为主机,usb外设作为从机进行数据通信.整个开发流程可以总结为以下几点: 1.发现设备 UsbManager usbManager = (UsbManager) context.getSystem

  • Android自定义TitleView标题开发实例

    Android开发过程中,经常遇到一个项目需要重复的定义相同样式的标题栏,Android相继推出了actionBar, toolBar, 相信有用到的朋友也会遇到一些不如意的时候,比如标题栏居中时,需要自定义xml文件给toolBar等,不了解actionBar,toolBar的可以去找相应的文章了解,这里介绍自定义titleBar满足国内主题风格样式的情况. 为了提前看到效果,先上效果图: 前期准备 1.为标题栏titleView预定义id,在values下的ids.xml中 <?xml ve

  • Android miniTwitter登录界面开发实例

    本文要演示的Android开发实例是如何完成一个Android中的miniTwitter登录界面,下面将分步骤讲解怎样实现图中的界面效果,让大家都能轻松的做出美观的登录界面. 先贴上最终要完成的效果图: miniTwitter登录界面的布局分析 首先由界面图分析布局,基本可以分为三个部分,下面分别讲解每个部分. 第一部分是一个带渐变色背景的LinearLayout布局,关于背景渐变色就不再贴代码了,效果如下图所示: 第二部分,红色线区域内,包括1,2,3,4 如图所示: 红色的1表示的是一个带圆

  • Android 应用指定浏览器开发实例

    本文主要讲解Android浏览器的开发实例,有三部分内容:启动Android默认浏览器.指定浏览器进行访问以及打开本地的html文件.      一.启动Android默认浏览器 Java代码 Intent intent = new Intent(); intent.setAction("android.intent.action.VIEW"); Uri content_url = Uri.parse("http://www.cnblogs.com"); inten

  • Android 矢量室内地图开发实例

    矢量室内地图开发 因为公司项目的需要,需要开发一套室内地图,并实现路线的规划功能.因为之前没做过这方面的开发,相关的资料也比较少,所以只能一个人去摸索.刚开始我是使用一般的位图去当作的地图,但是这个也让我在后面吃了不少的苦头. 我们知道地图一般都会有缩放和拖拽等功能,正当我把一样利用位图开发的地图样例时,我发现了不少的问题: 1.位图缩放会失真: 2.图片加载比较慢: 3.会导致客户端内存溢出 ... 因为这些问题,我不得不放弃这种方法.要解决上面的问题只能使用矢量图进行开发了,于是我使用了HT

  • android之App Widget开发实例代码解析

    Android Widget开发案例实现是本文要介绍的内容,主要是来了解并学习Android Widget开发应用,今天我们要写一下Android Widget的开发,由于快点凌晨,我就不说的太具体了,同志们就模仿吧! 首先继续了解下App Widget框架的主要的类: AppWidgetProvider:继承自BroadcastReceiver,在App Widget应用update,enable,disable和deleted时接受通知.其中onUpdate,onReceive是最常用到的方

  • Android编程实现仿优酷圆盘旋转菜单效果的方法详解【附demo源码下载】

    本文实例讲述了Android编程实现仿优酷圆盘旋转菜单效果的方法.分享给大家供大家参考,具体如下: 目前,用户对安卓应用程序的UI设计要求越来越高,因此,掌握一些新颖的设计很有必要. 比如菜单,传统的菜单已经不能满足用户的需求. 其中优酷中圆盘旋转菜单的实现就比较优秀,这里我提供下我的思路及实现,仅供参考. 该菜单共分里外三层导航菜单.可以依次从外向里关闭三层菜单,也可以反向打开,并且伴有圆盘旋转的动画效果 首先,看下效果: 以下是具体的代码及解释: 1. 菜单布局文件: 大家看到主要有三个Ra

  • Android编程实现仿优酷旋转菜单效果(附demo源码)

    本文实例讲述了Android编程实现仿优酷旋转菜单效果.分享给大家供大家参考,具体如下: 首先,看下效果: 不好意思,不会制作动态图片,只好上传静态的了,如果谁会,请教教我吧. 首先,看下xml文件: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" a

  • 关于Android高德地图的简单开发实例代码(DEMO)

    废话不多说了,直接给大家上干货了. 以下为初次接触时 ,练手的DEMO import android.app.Activity; import android.app.ProgressDialog; import android.content.ContentValues; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatab

随机推荐