在上一篇中,我们已经处理好了菜单的折叠和展开。如果你还没读过,可以点击下面的链接:
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。下面我们实现点击按钮,弹出提示框吧。进入下一节。