zoukankan      html  css  js  c++  java
  • (二)实现菜单动画

          在上一篇文章中,我们实现了界面的展现。如果你还没读过,请点击下面的链接:

    http://www.cnblogs.com/fuly550871915/p/4930470.html

          贴一张上一篇文章实现的效果图吧,如下:

          虽然我们将各个菜单都全部展现了出来,但是菜单的动画以及菜单的点击都还没有实现。在上一篇文章我们也分析了,如果将菜单的位置设定在红色按钮那里,然后给菜单设定补间动画,让其移动到图示位置,虽然动画实现了,会影响到点击事件。而属性动画虽然可以解决这个问题,但是它的向下兼容性不是很好,因此我们依旧坚持使用补间动画。那么我们要怎样解决这个难题呢?思路如下:

        我们让菜单的原本位置就为上图所示的位置,刚开始的时候让其不可见。然后当点击红色按钮的时候,我们给其设定动画,还是让其红色按钮移动到图示位置,然后让其可见。这样子,我们点击图示位置的按钮,就会有点击事件,就没什么影响了。其实就换一种角度,将其初始位置直接放在要移动的终点位置而不是起点位置。

            那么这个菜单的动画包括什么呢?首先是平移动画,每一个菜单平移的x方向和y方向的距离,与上一篇中我们在计算其位置的时的坐标是一样的。因此没什么难度,稍微修改先即可。然后就是平移的同时去旋转,旋转也很容易实现,没什么好说的。下面我们看一看实际的代码吧,然后再做解释。

            修改ArcMenu中的代码如下:

      1 package com.example.menu;
      2 
      3 import android.content.Context;
      4 import android.content.res.TypedArray;
      5 import android.util.AttributeSet;
      6 import android.util.TypedValue;
      7 import android.view.View;
      8 import android.view.View.OnClickListener;
      9 import android.view.animation.Animation;
     10 import android.view.animation.Animation.AnimationListener;
     11 import android.view.animation.AnimationSet;
     12 import android.view.animation.RotateAnimation;
     13 import android.view.animation.TranslateAnimation;
     14 import android.view.ViewGroup;
     15 
     16 public class ArcMenu extends ViewGroup implements OnClickListener{
     17     /**
     18      * 菜单按钮
     19      */
     20     private View mCBMenu;
     21     /**
     22      * 菜单的位置,为枚举类型
     23      * @author fuly1314
     24      *
     25      */
     26     private enum Position
     27     {
     28         LEFT_TOP,LEFT_BOTTOM,RIGHT_TOP,RIGHT_BOTTOM
     29     }
     30     /**
     31      * 菜单的状态
     32      * @author fuly1314
     33      *
     34      */
     35     private enum Status
     36     {
     37         OPEN,CLOSE
     38     }
     39     /**
     40      * 菜单为当前位置,默认为RIGHT_BOTTOM,在后面我们可以获取到
     41      */
     42     private Position mPosition = Position.RIGHT_BOTTOM;
     43     /**
     44      * 菜单的当前状态,默认为关闭
     45      */
     46     private Status mCurStatus = Status.CLOSE;
     47     
     48     /**
     49      * 菜单的半径,默认为120dp
     50      */
     51     private int mRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 150,
     52             getResources().getDisplayMetrics());
     53 
     54     
     55     
     56     public ArcMenu(Context context) {
     57         this(context,null);
     58     }
     59     public ArcMenu(Context context, AttributeSet attrs) {
     60         this(context,attrs,0);
     61     }
     62     public ArcMenu(Context context, AttributeSet attrs, int defStyle) {
     63         super(context, attrs, defStyle);
     64         
     65         TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ArcMenu, defStyle, 0);
     66         //获取到菜单设置的位置
     67         int position = ta.getInt(R.styleable.ArcMenu_position, 3);
     68         
     69         switch(position){
     70         case 0:
     71             mPosition = Position.LEFT_TOP;
     72             break;
     73         case 1:
     74             mPosition = Position.LEFT_BOTTOM;
     75             break;
     76         case 2:
     77             mPosition = Position.RIGHT_TOP;
     78             break;
     79         case 3:
     80             mPosition = Position.RIGHT_BOTTOM;
     81             break;
     82         }
     83         
     84         //获取到菜单的半径
     85         mRadius = (int) ta.getDimension(R.styleable.ArcMenu_radius,
     86                 TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 120,
     87                         getResources().getDisplayMetrics()));            
     88         ta.recycle();
     89         
     90     }
     91     
     92     
     93     
     94     /**
     95      * 测量各个子View的大小
     96      */
     97     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
     98     {
     99         int count = getChildCount();//获取子view的数量
    100         
    101         for(int i=0;i<count;i++)
    102         {
    103             //测量子view的大小
    104             measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);
    105         }
    106         
    107         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    108     }
    109 
    110     /**
    111      * 摆放各个子view的位置
    112      */
    113     protected void onLayout(boolean changed, int l, int t, int r, int b) {
    114         
    115         if(changed)//如果发生了改变,就重新布局
    116         {
    117             layoutMainMenu();//菜单按钮的布局
    118             /**
    119              * 下面的代码为菜单的布局
    120              */
    121             int count = getChildCount();
    122             
    123             for(int i=0;i<count-1;i++)
    124             {
    125                 View childView = getChildAt(i+1);//注意这里过滤掉菜单按钮,只要菜单选项view
    126                 
    127                 childView.setVisibility(GONE);//先让菜单消失
    128                 
    129                 int left = (int) (mRadius*Math.cos(Math.PI/2/(count-2)*i));
    130                 int top = (int) (mRadius*Math.sin(Math.PI/2/(count-2)*i));
    131 
    132                 
    133                 
    134                 switch(mPosition)
    135                 {
    136                 
    137                 case LEFT_TOP:
    138                     break;
    139                 case LEFT_BOTTOM:
    140                     top = getMeasuredHeight() - top-childView.getMeasuredHeight();
    141                     break;
    142                 case RIGHT_TOP:
    143                     left = getMeasuredWidth() - left-childView.getMeasuredWidth();
    144                     break;
    145                 case RIGHT_BOTTOM:
    146                     left = getMeasuredWidth() - left-childView.getMeasuredWidth();
    147                     top = getMeasuredHeight() - top-childView.getMeasuredHeight();
    148                     break;
    149                 }
    150                 
    151                 childView.layout(left, top, left+childView.getMeasuredWidth(),
    152                         top+childView.getMeasuredHeight());
    153             }
    154         }
    155 
    156         
    157     }
    158     /**
    159      * 菜单按钮的布局
    160      */
    161     private void layoutMainMenu() {
    162         
    163          mCBMenu = getChildAt(0);//获得主菜单按钮
    164          
    165          mCBMenu.setOnClickListener(this);
    166         
    167         int left=0;
    168         int top=0;
    169         
    170         switch(mPosition)
    171         {
    172         case LEFT_TOP:
    173             left = 0;
    174             top = 0;
    175             break;
    176         case LEFT_BOTTOM:
    177             left = 0;
    178             top = getMeasuredHeight() - mCBMenu.getMeasuredHeight();
    179             break;
    180         case RIGHT_TOP:
    181             left = getMeasuredWidth() - mCBMenu.getMeasuredWidth();
    182             top = 0;
    183             break;
    184         case RIGHT_BOTTOM:
    185             left = getMeasuredWidth() - mCBMenu.getMeasuredWidth();
    186             top = getMeasuredHeight() - mCBMenu.getMeasuredHeight();
    187             break;
    188         }
    189         
    190         mCBMenu.layout(left, top, left+mCBMenu.getMeasuredWidth(), top+mCBMenu.getMeasuredHeight());
    191     }
    192     /**
    193      * 菜单按钮的点击事件
    194      * @param v
    195      */
    196     public void onClick(View v) {
    197         //为菜单按钮设置点击动画
    198         RotateAnimation rAnimation = new RotateAnimation(0f, 720f, Animation.RELATIVE_TO_SELF, 0.5f, 
    199                 Animation.RELATIVE_TO_SELF, 0.5f);
    200         
    201         rAnimation.setDuration(300);
    202         
    203         rAnimation.setFillAfter(true);
    204         
    205         v.startAnimation(rAnimation);
    206         
    207         dealChildMenu(300);//处理菜单选项,比如折叠菜单或者展开菜单
    208         
    209     }
    210     /**
    211      * 处理菜单选项,比如折叠菜单或者展开菜单
    212      * @param duration 菜单选项的动画时间
    213      */
    214     private void dealChildMenu(int duration) 
    215     {
    216         
    217         //下面的代码为菜单选项设置动画
    218         
    219         int count = getChildCount();
    220         
    221         for(int i=0;i<count-1;i++)
    222         {
    223             final View childView = getChildAt(i+1);
    224             
    225             AnimationSet set = new AnimationSet(true);
    226             
    227             //1.首先是平移动画
    228             TranslateAnimation tAnimation = null;
    229             
    230             //平移的x方向和y方向的距离
    231             int x = (int) (mRadius*Math.cos(Math.PI/2/(count-2)*i));
    232             int y = (int) (mRadius*Math.sin(Math.PI/2/(count-2)*i));
    233             
    234             
    235             
    236             
    237             //平移的标志,是平移一个正数还以一个负数
    238             int xflag =1;
    239             int yflag =1;
    240         
    241             if(mPosition == Position.LEFT_TOP||mPosition == Position.LEFT_BOTTOM)
    242             {
    243                 xflag = -1;
    244             }
    245             if(mPosition == Position.LEFT_TOP||mPosition == Position.RIGHT_TOP)
    246             {
    247                 yflag = -1;
    248             }
    249             
    250             if(mCurStatus == Status.CLOSE)//如果当前状态为关闭则应该打开
    251             {
    252                  tAnimation = new TranslateAnimation(xflag*x, 0,
    253                         yflag*y, 0);
    254                 tAnimation.setDuration(duration);
    255                 tAnimation.setFillAfter(true);
    256                 
    257                 childView.setVisibility(VISIBLE);
    258                 
    259             }else//否则为打开状态,就应该关闭
    260             {
    261                  tAnimation = new TranslateAnimation( 0,xflag*x,
    262                             0,yflag*y);
    263                     tAnimation.setDuration(duration);
    264                     tAnimation.setFillAfter(true);
    265             }
    266             tAnimation.setStartOffset((i * 100) / count);
    267             tAnimation.setAnimationListener(new AnimationListener() {
    268                 
    269 
    270                 public void onAnimationStart(Animation animation) {
    271     
    272                     
    273                 }
    274                 
    275 
    276                 public void onAnimationRepeat(Animation animation) {
    277         
    278                     
    279                 }
    280                 
    281 
    282                 public void onAnimationEnd(Animation animation) {
    283 
    284                     if(mCurStatus == Status.CLOSE)
    285                     childView.setVisibility(GONE);
    286                 }
    287             });
    288             
    289             //2.然后是旋转动画
    290             RotateAnimation rAnimation = new RotateAnimation(0f, 0, Animation.RELATIVE_TO_SELF, 0.5f, 
    291                     Animation.RELATIVE_TO_SELF, 0.5f);
    292             rAnimation.setDuration(duration);
    293             rAnimation.setFillAfter(true);//动画结束是画面停留在此动画的最后一帧
    294             
    295             
    296             set.addAnimation(rAnimation);//一定要注意顺序,先旋转动画,然后再平移
    297             set.addAnimation(tAnimation);
    298             
    299             childView.startAnimation(set);
    300             
    301         }
    302         
    303         changeStatus();//动画完成后,要改变状态
    304         
    305     }
    306     /**
    307      * 改变状态
    308      */
    309     private void changeStatus() {
    310         
    311         mCurStatus = (mCurStatus == Status.CLOSE?Status.OPEN:Status.CLOSE);
    312         
    313     }
    314 
    315 }

          注意红色部分,是我们主要添加的代码。我们要求点击红色按钮的时候,展开菜单或者关闭菜单。因此,肯定在其点击事件里,调用处理菜单操作的方法了,即dealChildMenu(300);方法。在这个方法里,首先为每一个菜单设置平移动画,然后再为其设置旋转动画。注意,平移动画中,平移的距离,与红色按钮的方位有关,因此我们设置了xflag和yflag来标志在不同的方位,平移的距离的应该是一个正数还是一个负数。再就是点击红色按钮,是该展开菜单呢还是该折叠菜单,这与当前的状态有关。如果当前为展开状态,那么点击就应该关闭,当前为关闭状态,那么点击就应该展开。

          如果你对平移距离不是很懂,那么我建议你结合上面的代码,用笔在本子上好好画一画,分析分析。在这里我姑且就分析x方向的一种情况吧,作为一个引子。如下两张图:

          A是红色按钮,B是其中一个菜单。如左图的情况,根据我们的动画要求,B的位置一直就在图示位置,但是我们要用平移动画,让其从A点移动过来。那么A的x位置相对于B的x位置来说,不就是一个正值嘛。如果是右图的情况,那么A的x位置相对于B的x位置不就是一个负值嘛。因此x方向平移和y方向平移的值,是正是负,你可以一一分析,然后找出其中规律。在上面的代码中,已经写出来了。我就不再多说了。关键在于自己分析。

            然后运行程序,看看效果吧。如下:

          哈哈,还不错吧。快接近我们的目标了吧。下面我们就为每一个菜单添加点击动画

  • 相关阅读:
    如何用jquery实现实时监控浏览器宽度
    关于oracle with as用法
    SQL查询语句,怎样查询重复数据
    Axure RP Pro7.0的key注册码加汉化非破解
    秦曾昌人工智能课程---7、决策树集成学习Tree Ensembles
    秒懂机器学习---分类回归树CART
    秒懂机器学习---朴素贝叶斯
    秒懂机器学习---k临近算法(KNN)
    秒懂机器学习---机器学习无法逃避的梯度下降法
    秒懂机器学习---当机器学习遇上决策树....
  • 原文地址:https://www.cnblogs.com/fuly550871915/p/4930654.html
Copyright © 2011-2022 走看看