在上一篇中,我们已经处理好了菜单的折叠和展开。如果你还没读过,可以点击下面的链接:
http://www.cnblogs.com/fuly550871915/p/4930654.html

       贴出上一篇文章的效果图吧,如下:

      折叠和展开还不错。所写的代码也越来越简单,主要就是动画的添加而已。下面我们为每一个菜单添加点击动画。即,点击的时候,,让被点击的菜单放大消失,其他菜单缩小消失。

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

      红色部分是我们主要添加的代码。无非就是两个动画的添加,即缩放动画和透明度动画。没什么好说的,代码都写的很清晰了。然后要注意点击菜单后,要改变一下状态。因此点击菜单,所有的菜单都要消失。这个时候把状态改为关闭,是恰当的。然后我们运行一下效果,如下:

 

      好吧,模拟器上的效果还是不流畅。能在真机上实验要好一点。是不是越来越感觉代码写起来轻松了呢?确实是,主要的难点,也就是一个自定义的ViewGroup。下面我们实现点击按钮,弹出提示框吧。进入下一节。

posted on 2015-11-02 17:05  fuly  阅读(933)  评论(0编辑  收藏  举报