(四)实现菜单点击弹出提示框

      在上一篇文章中,我们给菜单的点击设置了动画,如果你没有阅读过,可以单击下面的链接:
http://www.cnblogs.com/fuly550871915/p/4930699.html

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

      下面我们要实现的逻辑也很简单,点击菜单,弹出一个提示框。怎么实现呢,只需要在ArcMenu中提供一个回调接口即可。这样子,我们就可以在MainActivity中重写回调方法,然后再ArcMenu中点击菜单时调用即可。

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

       红色部分是我们添加的主要代码。无非就是一个回调接口,没事什么好解释的了。

      下面修改MainActivity中的代码即可,如下:

 1 package com.example.menu;
 2 
 3 import com.example.menu.ArcMenu.ArcMenuListener;
 4 
 5 import android.os.Bundle;
 6 import android.view.View;
 7 import android.widget.Toast;
 8 import android.app.Activity;
 9 
10 public class MainActivity extends Activity implements ArcMenuListener {
11 
12     private ArcMenu menu;
13     @Override
14     protected void onCreate(Bundle savedInstanceState) {
15         super.onCreate(savedInstanceState);
16         setContentView(R.layout.activity_main);
17         
18         menu = (ArcMenu) findViewById(R.id.id_menu);
19         menu.setOnArcMenuListener(this);
20     }
21 
22 
23     public void dealMenuClick(View v) {
24         
25         Toast.makeText(this, "这是"+v.getTag(), Toast.LENGTH_SHORT).show();
26         
27     }
28     
29 }

        我们看红色部分的代码,重写了回调方法。无非就是获取之前布局中ImageView中设置的tag,然后把它放在提示框中罢了。运行程序效果如下:

       至此,我们的这个案例终结了。主要难点就是自定义ViewGroup,相信你通过这个案例,对自定义ViewGroup应该有了很好的了解了。

原文地址:https://www.cnblogs.com/fuly550871915/p/4930877.html