我们看一下实现的效果图:

在上图中,我将菜单弹出的效果设置成直线型,最终的弹出或汇总点在下面的红色按钮中。

  它的实现原理是设置动画的同时并利用动画中的插入器(interpolator)来实现弹力。主要用到了OvershootInterpolator和AnticipateOvershootInterpolator,简单介绍下这两个插入器。

  • OvershootInterpolator:表示向前甩一定值后再回到原来位置。
  • AnticipateOvershootInterpolator:表示开始的时候向后然后向前甩一定值后返回最后的值。

  当然还有其它的插入器,简要了解下其作用:

  • AnticipateInterpolator:表示开始的时候向后然后向前甩。
  • BounceInterpolator:表示动画结束的时候弹起。
  • OvershootInterpolator:表示向前甩一定值后再回到原来位置。
  • CycleInterpolator:表示动画循环播放特定的次数,速率改变沿着正弦曲线。
  • DecelerateInterpolator:表示在动画开始的地方快然后慢。
  • LinearInterpolator:表示以常量速率改变。

  我们可以通过一些示例加深对这几个插入器的了解。在API Demos中有些示例,大家去可以直接研究下API Demos中的Animation部分。

  具体可查看官方文档:http://developer.android.com/reference/android/view/animation/package-summary.html,这里不再详述。

MainActivity中的代码:

  1. package com.spring.menu.activity;
  2.  
  3. import com.spring.menu.R;
  4. import com.spring.menu.animation.SpringAnimation;
  5. import com.spring.menu.animation.EnlargeAnimationOut;
  6. import com.spring.menu.animation.ShrinkAnimationOut;
  7. import com.spring.menu.animation.ZoomAnimation;
  8. import com.spring.menu.utility.DeviceUtility;
  9.  
  10. import android.app.Activity;
  11. import android.os.Bundle;
  12. import android.view.View;
  13. import android.view.ViewGroup;
  14. import android.view.View.OnClickListener;
  15. import android.view.animation.Animation;
  16. import android.view.animation.AnimationUtils;
  17. import android.view.animation.AnticipateInterpolator;
  18. import android.widget.RelativeLayout;
  19.  
  20. /**
  21. * Android实现伸缩弹力分布菜单效果
  22. * @Description: Android实现伸缩弹力分布菜单效果
  23.  
  24. * @File: MainActivity.java
  25.  
  26. * @Package com.spring.menu.activity
  27.  
  28. * @Author Hanyonglu
  29.  
  30. * @Date 2012-10-25 下午09:41:31
  31.  
  32. * @Version V1.0
  33. */
  34. public class MainActivity extends Activity {
  35. private boolean areMenusShowing;
  36. private ViewGroup menusWrapper;
  37. private View imageViewPlus;
  38. private View shrinkRelativeLayout;
  39. private RelativeLayout layoutMain;
  40. // 顺时针旋转动画
  41. private Animation animRotateClockwise;
  42. // 你试着旋转动画
  43. private Animation animRotateAntiClockwise;
  44. private Class<?>[] intentActivity = {
  45. SecondActivity.class,ThreeActivity.class,FourActivity.class,
  46. SecondActivity.class,ThreeActivity.class,FourActivity.class};
  47. private int[] mainResources = {
  48. R.drawable.bg_main_1,R.drawable.bg_main_2,
  49. R.drawable.bg_main_3,R.drawable.bg_main_4,
  50. R.drawable.bg_main_1,R.drawable.bg_main_4};
  51.  
  52. /** Called when the activity is first created. */
  53. @Override
  54. public void onCreate(Bundle savedInstanceState) {
  55. super.onCreate(savedInstanceState);
  56. setContentView(R.layout.main_activity);
  57.  
  58. // 初始化
  59. initViews();
  60. }
  61.  
  62. // 初始化
  63. private void initViews(){
  64. imageViewPlus = findViewById(R.id.imageview_plus);
  65. menusWrapper = (ViewGroup) findViewById(R.id.menus_wrapper);
  66. shrinkRelativeLayout = findViewById(R.id.relativelayout_shrink);
  67. layoutMain = (RelativeLayout) findViewById(R.id.layout_content);
  68.  
  69. animRotateClockwise = AnimationUtils.loadAnimation(
  70. this,R.anim.rotate_clockwise);
  71. animRotateAntiClockwise = AnimationUtils.loadAnimation(
  72. this,R.anim.rotate_anticlockwise);
  73.  
  74. shrinkRelativeLayout.setOnClickListener(new OnClickListener() {
  75.  
  76. public void onClick(View v) {
  77. // TODO Auto-generated method stub
  78. showLinearMenus();
  79. }
  80. });
  81.  
  82. for (int i = ; i < menusWrapper.getChildCount(); i++) {
  83. menusWrapper.getChildAt(i).setOnClickListener(
  84. new SpringMenuLauncher(null,mainResources[i]));
  85. }
  86. }
  87.  
  88. /**
  89. * 以直线型展开菜单
  90. */
  91. private void showLinearMenus() {
  92. int[] size = DeviceUtility.getScreenSize(this);
  93.  
  94. if (!areMenusShowing) {
  95. SpringAnimation.startAnimations(
  96. this.menusWrapper, ZoomAnimation.Direction.SHOW, size);
  97. this.imageViewPlus.startAnimation(this.animRotateClockwise);
  98. } else {
  99. SpringAnimation.startAnimations(
  100. this.menusWrapper, ZoomAnimation.Direction.HIDE, size);
  101. this.imageViewPlus.startAnimation(this.animRotateAntiClockwise);
  102. }
  103.  
  104. areMenusShowing = !areMenusShowing;
  105. }
  106.  
  107. // 分布菜单事件监听器
  108. private class SpringMenuLauncher implements OnClickListener {
  109. private final Class<?> cls;
  110. private int resource;
  111.  
  112. private SpringMenuLauncher(Class<?> c,int resource) {
  113. this.cls = c;
  114. this.resource = resource;
  115. }
  116.  
  117. public void onClick(View v) {
  118. // TODO Auto-generated method stub
  119. MainActivity.this.startSpringMenuAnimations(v);
  120. layoutMain.setBackgroundResource(resource);
  121.  
  122. // MainActivity.this.startActivity(
  123. // new Intent(
  124. // MainActivity.this,
  125. // MainActivity.SpringMenuLauncher.this.cls));
  126. }
  127. }
  128.  
  129. /**
  130. * 展现菜单动画效果
  131. * @param view
  132. * @param runnable
  133. */
  134. private void startSpringMenuAnimations(View view) {
  135. areMenusShowing = true;
  136. Animation shrinkOut1 = new ShrinkAnimationOut();
  137. Animation growOut = new EnlargeAnimationOut();
  138. shrinkOut1.setInterpolator(new AnticipateInterpolator(2.0F));
  139. shrinkOut1.setAnimationListener(new Animation.AnimationListener() {
  140.  
  141. public void onAnimationEnd(Animation animation) {
  142. // TODO Auto-generated method stub
  143. MainActivity.this.imageViewPlus.clearAnimation();
  144. }
  145.  
  146. public void onAnimationRepeat(Animation animation) {
  147. // TODO Auto-generated method stub
  148.  
  149. }
  150.  
  151. public void onAnimationStart(Animation animation) {
  152. // TODO Auto-generated method stub
  153.  
  154. }
  155. });
  156.  
  157. view.startAnimation(growOut);
  158. }
  159. }

在点击红色按钮时弹出最上面的菜单,点击某个菜单时变换上面的背景图片,当然也可直接进入某个Activity。所以上面定义了 intentActivity和mainResources两个数组,分别代表切换的Activity和要变换的图片。大家可根据实际的需要进行设置。在 进行点击红色按钮时中间的加号向右进行旋转225度变成叉号,通过如下的动画:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <rotate
  3. xmlns:android="http://schemas.android.com/apk/res/android"
  4. android:interpolator="@android:anim/linear_interpolator"
  5. android:duration=""
  6. android:fromDegrees="0.0"
  7. android:toDegrees="225.0"
  8. android:pivotX="50.0%"
  9. android:pivotY="50.0%"
  10. android:fillAfter="true"
  11. android:fillEnabled="true"/>

再次点击则向左旋转还原,将上面的android:fromDegrees和android:toDegrees替换下即可。

下面了解下另一个重要的动画类是SpringAnimation,由它来控制各个菜单的动画效果,代码如下所示:

  1. package com.spring.menu.animation;
  2.  
  3. import com.spring.menu.control.ImageButtonExtend;
  4.  
  5. import android.view.View;
  6. import android.view.ViewGroup;
  7. import android.view.ViewGroup.MarginLayoutParams;
  8. import android.view.animation.AnticipateInterpolator;
  9. import android.view.animation.AnticipateOvershootInterpolator;
  10. import android.view.animation.OvershootInterpolator;
  11. import android.view.animation.TranslateAnimation;
  12.  
  13. /**
  14. * 分布菜单加载和伸缩动画
  15. * @Description: 分布菜单加载和伸缩动画
  16.  
  17. * @File: SpringAnimation.java
  18.  
  19. * @Package com.spring.menu.animation
  20.  
  21. * @Author Hanyonglu
  22.  
  23. * @Date 2012-10-25 下午12:18:39
  24.  
  25. * @Version V1.0
  26. */
  27. public class SpringAnimation extends ZoomAnimation {
  28. private static int[] size;
  29. private static int xOffset = ;
  30. private static int yOffset = -;
  31. public static final int DURATION = ;
  32.  
  33. /**
  34. * 构造器
  35. * @param direction
  36. * @param duration
  37. * @param view
  38. */
  39. public SpringAnimation(Direction direction, long duration, View view) {
  40. super(direction, duration, new View[] { view });
  41. SpringAnimation.xOffset = SpringAnimation.size[] / - ;
  42. }
  43.  
  44. /**
  45. * 开始显示动画效果
  46. * @param viewgroup
  47. * @param direction
  48. * @param size
  49. */
  50. public static void startAnimations(ViewGroup viewgroup,
  51. ZoomAnimation.Direction direction, int[] size) {
  52. SpringAnimation.size = size;
  53.  
  54. switch (direction) {
  55. case HIDE:
  56. startShrinkAnimations(viewgroup);
  57. break;
  58. case SHOW:
  59. startEnlargeAnimations(viewgroup);
  60. break;
  61. }
  62. }
  63.  
  64. /**
  65. * 开始呈现菜单
  66. * @param viewgroup
  67. */
  68. private static void startEnlargeAnimations(ViewGroup viewgroup) {
  69. for (int i = ; i < viewgroup.getChildCount(); i++) {
  70. if (viewgroup.getChildAt(i) instanceof ImageButtonExtend) {
  71. ImageButtonExtend inoutimagebutton = (ImageButtonExtend) viewgroup
  72. .getChildAt(i);
  73. SpringAnimation animation = new SpringAnimation(
  74. ZoomAnimation.Direction.HIDE, DURATION, inoutimagebutton);
  75. animation.setStartOffset((i * )
  76. / (- + viewgroup.getChildCount()));
  77. animation.setInterpolator(new OvershootInterpolator(4F));
  78. inoutimagebutton.startAnimation(animation);
  79. }
  80. }
  81. }
  82.  
  83. /**
  84. * 开始隐藏菜单
  85. * @param viewgroup
  86. */
  87. private static void startShrinkAnimations(ViewGroup viewgroup) {
  88. for (int i = ; i < viewgroup.getChildCount(); i++) {
  89. if (viewgroup.getChildAt(i) instanceof ImageButtonExtend) {
  90. ImageButtonExtend inoutimagebutton = (ImageButtonExtend) viewgroup
  91. .getChildAt(i);
  92. SpringAnimation animation = new SpringAnimation(
  93. ZoomAnimation.Direction.SHOW, DURATION,
  94. inoutimagebutton);
  95. animation.setStartOffset(( * ((- + viewgroup
  96. .getChildCount()) - i))
  97. / (- + viewgroup.getChildCount()));
  98. animation.setInterpolator(new AnticipateOvershootInterpolator(2F));
  99. inoutimagebutton.startAnimation(animation);
  100. }
  101. }
  102. }
  103.  
  104. @Override
  105. protected void addShrinkAnimation(View[] views) {
  106. // TODO Auto-generated method stub
  107. MarginLayoutParams mlp = (MarginLayoutParams) views[].
  108. getLayoutParams();
  109. addAnimation(new TranslateAnimation(
  110. xOffset + -mlp.leftMargin,
  111. 0F,yOffset + mlp.bottomMargin, 0F));
  112. }
  113.  
  114. @Override
  115. protected void addEnlargeAnimation(View[] views) {
  116. // TODO Auto-generated method stub
  117. MarginLayoutParams mlp = (MarginLayoutParams) views[].
  118. getLayoutParams();
  119. addAnimation(new TranslateAnimation(
  120. 0F, xOffset + -mlp.leftMargin,
  121. 0F,yOffset + mlp.bottomMargin));
  122. }
  123. }

该类继承自ZoomAnimation,关于ZoomAnimation代码如下:

  1. package com.spring.menu.animation;
  2.  
  3. import android.view.View;
  4. import android.view.animation.AnimationSet;
  5.  
  6. /**
  7. * 放大缩小动画类
  8. * @Description: 放大缩小动画类
  9.  
  10. * @File: ZoomAnimation.java
  11.  
  12. * @Package com.spring.menu.animation
  13.  
  14. * @Author Hanyonglu
  15.  
  16. * @Date 2012-10-25 下午11:37:52
  17.  
  18. * @Version V1.0
  19. */
  20. public abstract class ZoomAnimation extends AnimationSet {
  21. public Direction direction;
  22.  
  23. public enum Direction {
  24. HIDE, SHOW;
  25. }
  26.  
  27. public ZoomAnimation(Direction direction, long duration, View[] views) {
  28. super(true);
  29. this.direction = direction;
  30.  
  31. switch (this.direction) {
  32. case HIDE:
  33. addShrinkAnimation(views);
  34. break;
  35. case SHOW:
  36. addEnlargeAnimation(views);
  37. break;
  38. }
  39.  
  40. setDuration(duration);
  41. }
  42.  
  43. protected abstract void addShrinkAnimation(View[] views);
  44.  
  45. protected abstract void addEnlargeAnimation(View[] views);
  46. }

  有时我们为了增强用户体验,我们可以将直线设置成半圆形或是半椭圆形,可以利用Bresenham算法或是其它的方案实现半圆或半椭圆的菜单,而不是简单的将菜单定位在某个地方。关于这个,有兴趣的朋友可参阅相关资料去实现它。

  另外,上面的例子并没有实现动态的设置菜单的个数。个人觉得最好能动态设置菜单的布局,这样在添加或减少菜单时比较方便。一般的过 程是利用一个数组(代表图片资源),根据数组来实现它的布局。包括上段中提到的实现半圆形展开也要进行动态的设置。本来我想去实现它,但是真的没有那么多 时间,有需要的朋友可以去填充程序的SpringMenuLayout类,在这里我就不去实现它了。

  1. package com.spring.menu.layout;
  2.  
  3. /**
  4. * 实现伸缩弹力分布菜单布局类
  5. * @Description: 实现伸缩弹力分布菜单布局类
  6.  
  7. * @File: SpringMenuLayout.java
  8.  
  9. * @Package com.spring.menu.layout
  10.  
  11. * @Author Hanyonglu
  12.  
  13. * @Date 2012-10-26 下午07:57:56
  14.  
  15. * @Version V1.0
  16. */
  17. public class SpringMenuLayout {
  18. // 自动生成直线型布局
  19.  
  20. // 自动生成圆弧型布局
  21. }

以上是关于Android中实现伸缩弹力分布菜单效果的实现过程,由于本篇不算是原创性的文章,所以关于代码没有过多的讲解,具体的代码讲解可参考原创文章:http://www.cnblogs.com/mudoot/archive/2012/01/19/path_composer_menu.html ,同时也非常感谢原创作者提供的资料。

示例下载:/Files/hanyonglu/AndroidFile/MySpringMenu.rar

Github地址:https://github.com/hanyonglu/Android-Spring-Menu

Path2.0中绚丽的的旋转菜单的更多相关文章

  1. Android 实现Path2.0中绚丽的的旋转菜单

    上图先: 那么下面开始吧~ 首先,将整个菜单动画分解开来. 1.       一级菜单按钮的旋转动画2个,十字和叉叉状态的转换. 2.       二级菜单按钮的平移动画2个,弹簧效果的in和out ...

  2. android圆形旋转菜单,而对于移动转换功能支持

    LZ该公司最近接手一个项目,需要写一个圆形旋转菜单,和菜单之间的移动换位支持,我本来以为这样的demo如若互联网是非常.想想你妈妈也帮不了我,空旋转,但它不能改变位置,所以LZ我们只能靠自己摸索. 最 ...

  3. 3D旋转菜单

    今天来个3D旋转菜单,是纯css3实现的,主要用到transform,transition,backface-visibility. 主要是transform这个变换,它是今天猪脚. transfor ...

  4. jQuery Wheel Menu:实现漂亮的 Path 风格旋转菜单

    相信很多用过 Path 的都对它的独特的旋转导航菜单有深刻的印象,这个功能也被很多的 Web 开发者模仿.今天分享的这款插件可以方便的在你的网站中加入和 Path 一样的旋转菜单,可以自定义效果. 您 ...

  5. 在PyQt中构建 Python 菜单栏、菜单和工具栏

    摘要:菜单.工具栏和状态栏是大多数GUI 应用程序的常见且重要的图形组件.您可以使用它们为您的用户提供一种快速访问应用程序选项和功能的方法. 本文分享自华为云社区<Python 和 PyQt:创 ...

  6. 在 NetBeans IDE 6.0 中分析 Java 应用程序性能

    NetBeans IDE 6.0 包含一个强大的性能分析工具,可提供与应用程序运行时行为有关的重要信息.通过 NetBeans 性能分析工具,我们可以方便地在 IDE 中监控应用程序的线程状态.CPU ...

  7. xcode 5.0中,新的开发者证书加载方式

    按照先前从网上看到的参考,开通了开发者账号之后,要先在本地生成一个request文件,然后上传苹果开发者网站,然后在官网上生成一个证书.cer文件,拿这个文件在本地生成p12文件,然后就是一堆鸡零狗碎 ...

  8. 有关OpenCV1.0中GUI命令的几个函数学习总结

    1.修改窗口背景色或者光标形状 在OpenCV1.0版本利用函数int cvNamedWindow( const char* name, int flags )初始化创建一个窗口后,窗口的背景色是灰色 ...

  9. OpenGL立方体在世界坐标系中_缩放_旋转_平移_顶点片源着色器_光照作用_棋盘纹理贴图

    读取bmp等图片格式中的像素还有难度,就先用这个棋盘图象素来弄了 代码打错一个就一直First-chance exception ,貌似还有一个要用q或者Q才能成功退出,不知道缺少哪句,我用窗口红叉退 ...

随机推荐

  1. 剑指offer三十五之数组中的逆序对

    一.题目 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出. 即输出P%1000 ...

  2. (转)Python3.5——装饰器及应用详解

    原文:https://blog.csdn.net/loveliuzz/article/details/77853346 Python3.5——装饰器及应用详解(下)----https://blog.c ...

  3. 泛型深入--java泛型的继承和实现、泛型擦除

    泛型实现类: package generic; /** * 泛型父类:子类为“富二代”:子类的泛型要比父类多 * 1,保留父类的泛型-->子类为泛型类 * 2,不保留父类泛型-->子类按需 ...

  4. C#设计模式系列目录

    http://www.cnblogs.com/libingql/archive/2012/04/16/2451608.html 抽空,学习,加强!

  5. start with connect by prior

    start with connect by prior的使用: select … from tablename start with 条件1 connect by 条件2 where 条件3; sta ...

  6. Java基础知识01

    1. String,StringBuffer和StringBuilder的区别? String:final修饰,String对象创建后不可修改:StringBuffer和StringBuilder对象 ...

  7. facebook 摘要生成阅读笔记(一) A Neural Attention Model for Sentence Summarization

    流程: 1.文本和摘要全部输入到模型中. 2.训练时,对生成摘要取前C个词,从头开始取,如果生成的摘要不足C,那么不足的地方直接补<s>. 3.训练时,最大化生成的摘要与原摘要的概率,即每 ...

  8. linux下c的网络编程---转载

    1.tcp协议

  9. 功能------常用快捷键(在win10下)

    功能------win10 常用快捷键 在进行学习,记录,编写代码时,需要用到一些功能,用鼠标浪费时间,可以使用快捷键来快速的处理.方便操作. 以下内容分为两类.快捷键以及触控板类(不能享用鼠标) 快 ...

  10. SQL2008无法连接到(local),该账户当前被锁定,所以Sa用户登陆失败

    1 安装小结 换了电脑,很多软件都得重装,期间报了很多问题,比如说先装vs2008再装sql server2008r2会报一个“存在2008早期版本”,通过查找,百度一系列的坑爹之路后,我还是把vs2 ...