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

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索android
, 旋转菜单
圆形旋转菜单
android 圆形旋转菜单、html5旋转圆形菜单、html5旋转半圆形菜单、圆形旋转导航菜单、jquery圆形旋转菜单,以便于您获取更多的相关知识。

时间: 2024-09-16 14:27:22

Android圆形旋转菜单开发实例_Android的相关文章

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

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

Android 应用指定浏览器开发实例_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"); i

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

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

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

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

Android中的指纹识别demo开发实例_Android

 指纹识别是在Android 6.0之后新增的功能,因此在使用的时候需要先判断用户手机的系统版本是否支持指纹识别.另外,实际开发场景中,使用指纹的主要场景有两种: 纯本地使用.即用户在本地完成指纹识别后,不需要将指纹的相关信息给后台. 与后台交互.用户在本地完成指纹识别后,需要将指纹相关的信息传给后台. 由于使用指纹识别功能需要一个加密对象(CryptoObject)该对象一般是由对称加密或者非对称加密获得.上述两种开发场景的实现大同小异,主要区别在于加密过程中密钥的创建和使用,一般来说,纯本地

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

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

Android开发之ViewSwitcher用法实例_Android

本文实例讲述了Android开发之ViewSwitcher用法.分享给大家供大家参考,具体如下: android.widget.ViewSwitcher是ViewAnimator的子类,用于在两个View之间切换,但每次只能显示一个View. ViewSwitcher的addView函数的代码如下: /** * {@inheritDoc} * * @throws IllegalStateException if this switcher already contains two childre

Android开发之Service用法实例_Android

本文实例讲述了Android开发之Service用法.分享给大家供大家参考.具体分析如下: Service是一个生命周期较长而且没有界面的程序. 下面通过一个播放mp3的例子来学习. 先看MainActivity.java package com.example.servicetest; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view

Android WebView 应用界面开发教程_Android

WebView组件本身就是一个浏览器实现,Android5.0增强的WebView基于Chromium M37,直接支持WebRTC.WebAudio.WebGL.开发者可以直接在WebView中使用聚合(Polymer)和Material设计. 一.WebView浏览网页(加载线上URL) WebView提供了很多方法执行浏览器操作,常用方法如下: void goBack():后退 void goForward():前进. void goBackOrForward(int step):step