热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

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(); 
    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  -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 

这里旋转是根据初始化时每个菜单所在的位置来求的旋转角度,然后启动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)布局文件:

 

(2)菜单布局文件:

<&#63;xml version="1.0" encoding="utf-8"&#63;> 
 
   
   
 

(3)Activity中调用

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


推荐阅读
  • nginx+tomcat session 共享
    *tomcat1192.168.10.153*tomcat2192.168.10.154Tomcat工作模式必须为Nio模式。##添加如下内容,注意更换address ... [详细]
  • MyBatis模糊查询和多条件查询一、ISmbmsUserDao层根据姓名模糊查询publicListgetUser();多条件查询publicList ... [详细]
  • lora物联网开发教程(物联网lora特点)
    长距离星型架构,由于长距离连接性,从而减少了电池寿命。这个协议采用了阿罗哈法。在一个网状网络或者一个异步网络中,例如蜂窝网,结点必须频繁的被唤醒,来同步网络和检查消息。这种同步,大 ... [详细]
  • 载波|等份_NR SRS时频域位置
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了NRSRS时频域位置相关的知识,希望对你有一定的参考价值。微信同步更新欢迎关注同名modem协议笔记S ... [详细]
  • Android的四种启动模式
     对Android的启动模式不是很了解,这里记录下简单的理解内容以便日后查看。 Androi的四种启动模式分别为:standard,singleTop,singleTask,sing ... [详细]
  • 一、使用ContentProvider(内容提供者)共享数据ContentProvider在android中的作用是对外共享数据,也就是说 ... [详细]
  • 一、在androidStudio中实现tabs比较简单,新建项目就可以选择tabs模板进行创建,默认实现tabs功能:直接运行项目就可以看到效果:可以说非常简单,但是我们在实际开发 ... [详细]
  • apk简单介绍APK的组成apk安装流程app的启动过程apk打包流程AIDLAIDL介绍为什么要设计这门语言它有哪些语法?默认支持的数据类型包括什么是apk打包流程 ... [详细]
  • kafkamanager(cmak)安装及使用
    1.软件下载kafka-manager工具目前改名为cmak,下载地址为:https:github.comyahooCMAKreleasestag3.0.0.5现在 ... [详细]
  • intellij idea修改maven配置时总是恢复默认配置的解决方法idea版本(2020.2.x)_java
    这篇文章主要介绍了intellijidea修改maven配置时总是恢复默认配置的解决方法idea版本(2020.2.x),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考 ... [详细]
  • 大数据分析Python有哪些爬虫框架
    一、ScrapyScrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。。用 ... [详细]
  • nvmw安装,用于控制node版本;
    之前一直使用的是nodev2.2.0版本,挺说新版本的node解决了npm安装插件产生文件夹结构过深的问题,所以就想更新试试;上网一看才发现,尼玛的node已经到了6.+版本了,好 ... [详细]
  • hibernate映射组件映射
    在Hibernate中,component是某个实体的逻辑组成部分,它与实体的根本区别是没有oid(对象标识符),compo ... [详细]
  • 在ROS系统中,参数读写一般通过xml或者yaml格式的文件,其中yaml用得比较多。这是一种可读性高,轻量级的标记语言,简单好用。对于yaml文件,ros中用的较早版本的yaml- ... [详细]
  • 如何理解MyBatis动态SQL
    本篇内容主要讲解“如何理解MyBatis动态SQL”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何理解M ... [详细]
author-avatar
多少年都不会变
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有