(二)实现菜单动画
2015-11-02 16:52
471 查看
在上一篇文章中,我们实现了界面的展现。如果你还没读过,请点击下面的链接:
/article/6123632.html
贴一张上一篇文章实现的效果图吧,如下:
虽然我们将各个菜单都全部展现了出来,但是菜单的动画以及菜单的点击都还没有实现。在上一篇文章我们也分析了,如果将菜单的位置设定在红色按钮那里,然后给菜单设定补间动画,让其移动到图示位置,虽然动画实现了,会影响到点击事件。而属性动画虽然可以解决这个问题,但是它的向下兼容性不是很好,因此我们依旧坚持使用补间动画。那么我们要怎样解决这个难题呢?思路如下:
那么这个菜单的动画包括什么呢?首先是平移动画,每一个菜单平移的x方向和y方向的距离,与上一篇中我们在计算其位置的时的坐标是一样的。因此没什么难度,稍微修改先即可。然后就是平移的同时去旋转,旋转也很容易实现,没什么好说的。下面我们看一看实际的代码吧,然后再做解释。
修改ArcMenu中的代码如下:
注意红色部分,是我们主要添加的代码。我们要求点击红色按钮的时候,展开菜单或者关闭菜单。因此,肯定在其点击事件里,调用处理菜单操作的方法了,即dealChildMenu(300);方法。在这个方法里,首先为每一个菜单设置平移动画,然后再为其设置旋转动画。注意,平移动画中,平移的距离,与红色按钮的方位有关,因此我们设置了xflag和yflag来标志在不同的方位,平移的距离的应该是一个正数还是一个负数。再就是点击红色按钮,是该展开菜单呢还是该折叠菜单,这与当前的状态有关。如果当前为展开状态,那么点击就应该关闭,当前为关闭状态,那么点击就应该展开。
如果你对平移距离不是很懂,那么我建议你结合上面的代码,用笔在本子上好好画一画,分析分析。在这里我姑且就分析x方向的一种情况吧,作为一个引子。如下两张图:
A是红色按钮,B是其中一个菜单。如左图的情况,根据我们的动画要求,B的位置一直就在图示位置,但是我们要用平移动画,让其从A点移动过来。那么A的x位置相对于B的x位置来说,不就是一个正值嘛。如果是右图的情况,那么A的x位置相对于B的x位置不就是一个负值嘛。因此x方向平移和y方向平移的值,是正是负,你可以一一分析,然后找出其中规律。在上面的代码中,已经写出来了。我就不再多说了。关键在于自己分析。
然后运行程序,看看效果吧。如下:
哈哈,还不错吧。快接近我们的目标了吧。下面我们就为每一个菜单添加点击动画
/article/6123632.html
贴一张上一篇文章实现的效果图吧,如下:
虽然我们将各个菜单都全部展现了出来,但是菜单的动画以及菜单的点击都还没有实现。在上一篇文章我们也分析了,如果将菜单的位置设定在红色按钮那里,然后给菜单设定补间动画,让其移动到图示位置,虽然动画实现了,会影响到点击事件。而属性动画虽然可以解决这个问题,但是它的向下兼容性不是很好,因此我们依旧坚持使用补间动画。那么我们要怎样解决这个难题呢?思路如下:
我们让菜单的原本位置就为上图所示的位置,刚开始的时候让其不可见。然后当点击红色按钮的时候,我们给其设定动画,还是让其红色按钮移动到图示位置,然后让其可见。这样子,我们点击图示位置的按钮,就会有点击事件,就没什么影响了。其实就换一种角度,将其初始位置直接放在要移动的终点位置而不是起点位置。
那么这个菜单的动画包括什么呢?首先是平移动画,每一个菜单平移的x方向和y方向的距离,与上一篇中我们在计算其位置的时的坐标是一样的。因此没什么难度,稍微修改先即可。然后就是平移的同时去旋转,旋转也很容易实现,没什么好说的。下面我们看一看实际的代码吧,然后再做解释。
修改ArcMenu中的代码如下:
package com.example.menu; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.util.TypedValue; import android.view.View; import android.view.View.OnClickListener; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; import android.view.animation.AnimationSet; import android.view.animation.RotateAnimation; import android.view.animation.TranslateAnimation; import android.view.ViewGroup; public class ArcMenu extends ViewGroup implements OnClickListener{ /** * 菜单按钮 */ private View mCBMenu; /** * 菜单的位置,为枚举类型 * @author fuly1314 * */ private enum Position { LEFT_TOP,LEFT_BOTTOM,RIGHT_TOP,RIGHT_BOTTOM } /** * 菜单的状态 * @author fuly1314 * */ private enum Status { OPEN,CLOSE } /** * 菜单为当前位置,默认为RIGHT_BOTTOM,在后面我们可以获取到 */ private Position mPosition = Position.RIGHT_BOTTOM; /** * 菜单的当前状态,默认为关闭 */ private Status mCurStatus = Status.CLOSE; /** * 菜单的半径,默认为120dp */ private int mRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 150, getResources().getDisplayMetrics()); public ArcMenu(Context context) { this(context,null); } public ArcMenu(Context context, AttributeSet attrs) { this(context,attrs,0); } public ArcMenu(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ArcMenu, defStyle, 0); //获取到菜单设置的位置 int position = ta.getInt(R.styleable.ArcMenu_position, 3); switch(position){ case 0: mPosition = Position.LEFT_TOP; break; case 1: mPosition = Position.LEFT_BOTTOM; break; case 2: mPosition = Position.RIGHT_TOP; break; case 3: mPosition = Position.RIGHT_BOTTOM; break; } //获取到菜单的半径 mRadius = (int) ta.getDimension(R.styleable.ArcMenu_radius, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 120, getResources().getDisplayMetrics())); ta.recycle(); } /** * 测量各个子View的大小 */ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int count = getChildCount();//获取子view的数量 for(int i=0;i<count;i++) { //测量子view的大小 measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec); } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } /** * 摆放各个子view的位置 */ protected void onLayout(boolean changed, int l, int t, int r, int b) { if(changed)//如果发生了改变,就重新布局 { layoutMainMenu();//菜单按钮的布局 /** * 下面的代码为菜单的布局 */ int count = getChildCount(); for(int i=0;i<count-1;i++) { View childView = getChildAt(i+1);//注意这里过滤掉菜单按钮,只要菜单选项view childView.setVisibility(GONE);//先让菜单消失 int left = (int) (mRadius*Math.cos(Math.PI/2/(count-2)*i)); int top = (int) (mRadius*Math.sin(Math.PI/2/(count-2)*i)); switch(mPosition) { case LEFT_TOP: break; case LEFT_BOTTOM: top = getMeasuredHeight() - top-childView.getMeasuredHeight(); break; case RIGHT_TOP: left = getMeasuredWidth() - left-childView.getMeasuredWidth(); break; case RIGHT_BOTTOM: left = getMeasuredWidth() - left-childView.getMeasuredWidth(); top = getMeasuredHeight() - top-childView.getMeasuredHeight(); break; } childView.layout(left, top, left+childView.getMeasuredWidth(), top+childView.getMeasuredHeight()); } } } /** * 菜单按钮的布局 */ private void layoutMainMenu() { mCBMenu = getChildAt(0);//获得主菜单按钮 mCBMenu.setOnClickListener(this); int left=0; int top=0; switch(mPosition) { case LEFT_TOP: left = 0; top = 0; break; case LEFT_BOTTOM: left = 0; top = getMeasuredHeight() - mCBMenu.getMeasuredHeight(); break; case RIGHT_TOP: left = getMeasuredWidth() - mCBMenu.getMeasuredWidth(); top = 0; break; case RIGHT_BOTTOM: left = getMeasuredWidth() - mCBMenu.getMeasuredWidth(); top = getMeasuredHeight() - mCBMenu.getMeasuredHeight(); break; } mCBMenu.layout(left, top, left+mCBMenu.getMeasuredWidth(), top+mCBMenu.getMeasuredHeight()); } /** * 菜单按钮的点击事件 * @param v */ public void onClick(View v) { //为菜单按钮设置点击动画 RotateAnimation rAnimation = new RotateAnimation(0f, 720f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); rAnimation.setDuration(300); rAnimation.setFillAfter(true); v.startAnimation(rAnimation); dealChildMenu(300);//处理菜单选项,比如折叠菜单或者展开菜单 } /** * 处理菜单选项,比如折叠菜单或者展开菜单 * @param duration 菜单选项的动画时间 */ 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 } }
注意红色部分,是我们主要添加的代码。我们要求点击红色按钮的时候,展开菜单或者关闭菜单。因此,肯定在其点击事件里,调用处理菜单操作的方法了,即dealChildMenu(300);方法。在这个方法里,首先为每一个菜单设置平移动画,然后再为其设置旋转动画。注意,平移动画中,平移的距离,与红色按钮的方位有关,因此我们设置了xflag和yflag来标志在不同的方位,平移的距离的应该是一个正数还是一个负数。再就是点击红色按钮,是该展开菜单呢还是该折叠菜单,这与当前的状态有关。如果当前为展开状态,那么点击就应该关闭,当前为关闭状态,那么点击就应该展开。
如果你对平移距离不是很懂,那么我建议你结合上面的代码,用笔在本子上好好画一画,分析分析。在这里我姑且就分析x方向的一种情况吧,作为一个引子。如下两张图:
A是红色按钮,B是其中一个菜单。如左图的情况,根据我们的动画要求,B的位置一直就在图示位置,但是我们要用平移动画,让其从A点移动过来。那么A的x位置相对于B的x位置来说,不就是一个正值嘛。如果是右图的情况,那么A的x位置相对于B的x位置不就是一个负值嘛。因此x方向平移和y方向平移的值,是正是负,你可以一一分析,然后找出其中规律。在上面的代码中,已经写出来了。我就不再多说了。关键在于自己分析。
然后运行程序,看看效果吧。如下:
哈哈,还不错吧。快接近我们的目标了吧。下面我们就为每一个菜单添加点击动画
相关文章推荐
- Android程序开发:简单电话拨号器
- oracle11g分页优化,rowid和rownum的性能比较,解决越往后数据查询越慢的问题
- 与企业某老师的一次谈话
- JS 加法函数,用来得到精确的加法结果
- 支持设置数据为空时打底view的RecyclerView+支持RecyclerView的CursorAdapter
- 【LEETCODE】102-Binary Tree Level Order Traversal
- linux下安装MYSQL错误:conflicts with file from package mysql-libs-*的解决方法
- iOS 应用程序图标数字角标
- 基于视频的车辆检测(c语言)
- 服务器监控客户端系统状态4.0
- 什么事arc
- 第8周项目1 - 建立顺序串的算法库
- dijkstra算法的实现。
- 第十周 项目2-二叉树遍历的递归算法
- 王亟亟的Python学习之路(四)-循环,条件,Range,list和tuple
- 矩形覆盖
- 第8周项目4-字符串加密
- 王亟亟的Python学习之路(四)-循环,条件,Range,list和tuple
- Android移动view动画问题
- Scala学习——高阶函数