最近真的是忙死了,做了很久的这个菜单动画特效,都没有时间写博客,今天在机场等飞机终于有了空闲时间。
上图先:
那么下面开始吧~
首先,将整个菜单动画分解开来。
1. 一级菜单按钮的旋转动画2个,十字和叉叉状态的转换。
2. 二级菜单按钮的平移动画2个,弹簧效果的in和out。
3. 二级菜单按钮的点击效果,放大消失,其他未点击按钮缩小消失。
4. 一级菜单按钮的恢复效果,放大出现。
View Row Code
1<?xml version="1.0" encoding="UTF-8"?>2<rotate3 xmlns:android="http://schemas.android.com/apk/res/android"4 android:interpolator="@android:anim/linear_interpolator"5 android:duration="150"6 android:fromDegrees="0.0"7 android:toDegrees="-225.0"8 android:pivotX="50.0%"9 android:pivotY="50.0%"10 android:fillAfter="true"11 android:fillEnabled="true"12 />rotate_story_add_button_out.xml
View Row Code
1<?xml version="1.0" encoding="UTF-8"?>2<rotate3 xmlns:android="http://schemas.android.com/apk/res/android"4 android:interpolator="@android:anim/linear_interpolator"5 android:duration="150"6 android:fromDegrees="-225.0"7 android:toDegrees="0.0"8 android:pivotX="50.0%"9 android:pivotY="50.0%"10 android:fillAfter="true"11 android:fillEnabled="true"12 />这2段没什么好说的,定义好角度即可。
接下来是需要我们在代码中定义的动画部分,这几个动画的部分需要定义一个基类,作为统一的调用接口,这个基类被称作InOutAnimation,继承自AnimationSet,这个基类的主要工作是为view提供in和out两种不同的状态时的动画效果。其子类需要实现2个方法:
好的 逐一去实现:
首先是一级菜单按钮的旋转动画,这2个动画可以直接在xml中定义,然后load到代码中来,具体代码如下:
rotate_story_add_button_in.xml
View Row Code
1protected abstract void addInAnimation(View aview[]);2protected abstract void addOutAnimation(View aview[]);从而进行view的入场和离场动画。
下面是InOutAnimation的代码部分:
View Row Code
1public abstract class InOutAnimationextends AnimationSet {2 3 publicDirection direction;4 5 publicenum Direction {6 IN,OUT;7 }8 9 publicInOutAnimation(Direction direction,long l, View[] aview) {10 super(true);11 this.direction = direction;12 switch (this.direction) {13 caseIN:14 addInAnimation(aview);15 break;16 caseOUT:17 addOutAnimation(aview);18 19 break;20 }21 setDuration(l);22 }23 24 protectedabstract void addInAnimation(View aview[]);25 26 protectedabstract void addOutAnimation(View aview[]);27 28}接下来就是重头戏啦,二级菜单按钮的平移动画。
这部分动画看起来可能会比较复杂和神秘,其实不然,当把整个动画过程分解开来的时候,都是最最简单的平移而已,我们要做的只是定义一下平移的起点和终点、开始动画的顺序以及插值(Interpolator),让整个过程看起来很炫。
先说动画的起点和终点吧,起点很简单,就是整个view的左下角,即0,0点,为了效果漂亮一些,我们稍微的将左下角位置定义的有一些偏移,经验上的值是16,-13,这个点的位置看你心情而定咯~ 好 终点就是你想让他在的点上就好了,终点我们将定义到layout中去,为这个2级菜单指定一个margin的值就好。
还是上代码比较直观:
动画如下:
View Row Code
1收缩部分:TranslateAnimation(xOffset+ -mlp.leftMargin, 0F,yOffset + mlp.bottomMargin, 0F)2扩张部分:TranslateAnimation(0F, xOffset+ -mlp.leftMargin, 0F,yOffset + mlp.bottomMargin)位置定义部分:
例如:
android:layout_marginBottom="142dp" android:layout_marginLeft="10.667dp"
这个位置大家可以直观的在布局文件中看到,详细的布局文件也将在下面展示。
以上是单独的每一个二级按钮的动画,而组合的动画就是指定了一下开始的时间差以及插值:
这个就是奥妙所在了,OvershootInterpolator AnticipateInterpolator 这2个插值器提供了弹力效果。
整段的代码如下:
View Row Code
1public class ComposerButtonAnimation extends InOutAnimation {2 3 publicstatic final int DURATION = 500;4 privatestatic final int xOffset = 16;5 privatestatic final int yOffset = -13;6 7 publicComposerButtonAnimation(Direction direction,long l, View view) {8 super(direction, l,new View[] { view });9 }10 11 publicstatic void startAnimations(ViewGroup viewgroup,12 InOutAnimation.Direction direction) {13 switch (direction) {14 caseIN:15 startAnimationsIn(viewgroup);16 break;17 caseOUT:18 startAnimationsOut(viewgroup);19 break;20 }21 }22 23 privatestatic void startAnimationsIn(ViewGroup viewgroup) {24 for (int i= 0; i < viewgroup.getChildCount(); i++) {25 if (viewgroup.getChildAt(i) instanceof InOutImageButton) {26 InOutImageButton inoutimagebutton = (InOutImageButton) viewgroup27 .getChildAt(i);28 ComposerButtonAnimation animation = new ComposerButtonAnimation(29 InOutAnimation.Direction.IN,DURATION, inoutimagebutton);30 animation.setStartOffset((i* 100)31 / (-1+ viewgroup.getChildCount()));32 animation.setInterpolator(newOvershootInterpolator(2F));33 inoutimagebutton.startAnimation(animation);34 }35 }36 }37 38 privatestatic void startAnimationsOut(ViewGroup viewgroup) {39 for (int i= 0; i < viewgroup.getChildCount(); i++) {40 if (viewgroup.getChildAt(i) instanceof InOutImageButton) {41 InOutImageButton inoutimagebutton = (InOutImageButton) viewgroup42 .getChildAt(i);43 ComposerButtonAnimation animation = new ComposerButtonAnimation(44 InOutAnimation.Direction.OUT,DURATION,45 inoutimagebutton);46 animation.setStartOffset((100* ((-1+ viewgroup47 .getChildCount())- i))48 / (-1+ viewgroup.getChildCount()));49 animation.setInterpolator(newAnticipateInterpolator(2F));50 inoutimagebutton.startAnimation(animation);51 }52 }53 }54 55 @Override56 protectedvoid addInAnimation(View[] aview) {57 MarginLayoutParams mlp= (MarginLayoutParams) aview[0]58 .getLayoutParams();59 addAnimation(new TranslateAnimation(xOffset+ -mlp.leftMargin, 0F,60 yOffset+ mlp.bottomMargin, 0F));61 }62 63 @Override64 protectedvoid addOutAnimation(View[] aview) {65 MarginLayoutParams mlp= (MarginLayoutParams) aview[0]66 .getLayoutParams();67 addAnimation(new TranslateAnimation(0F, xOffset+ -mlp.leftMargin, 0F,68 yOffset+ mlp.bottomMargin));69 }70}剩下的增大出现、增大消失及缩小消失都是scale和alpha的组合动画。
例如增大出现为:
ComposerButtonAnimation.java
View Row Code
1addAnimation(newScaleAnimation(0F, 1F, 0F, 1F, 1, 0.5F, 1, 0.5F));2addAnimation(newAlphaAnimation(0F, 1F));View Row Code
1public class ComposerButtonGrowAnimationIn extends InOutAnimation {2 3 publicComposerButtonGrowAnimationIn(int i) {4 super(InOutAnimation.Direction.IN, i,new View[0]);5 }6 7 @Override8 protectedvoid addInAnimation(View[] aview) {9 addAnimation(new ScaleAnimation(0F,1F, 0F, 1F, 1, 0.5F, 1, 0.5F));10 addAnimation(new AlphaAnimation(0F,1F));11 12 }13 14 @Override15 protectedvoid addOutAnimation(View[] aview) {}16 17}18 19public class ComposerButtonGrowAnimationOut extends InOutAnimation {20 21 publicComposerButtonGrowAnimationOut(int i) {22 super(InOutAnimation.Direction.OUT, i,new View[0]);23 }24 25 @Override26 protectedvoid addInAnimation(View[] aview) {}27 28 @Override29 protectedvoid addOutAnimation(View[] aview) {30 addAnimation(new ScaleAnimation(1F,5F, 1F, 5F, 1, 0.5F, 1, 0.5F));31 addAnimation(new AlphaAnimation(1F,0F));32 }33 34} public class ComposerButtonShrinkAnimationOut extends InOutAnimation {35 36 publicComposerButtonShrinkAnimationOut(int i) {37 super(InOutAnimation.Direction.OUT, i,new View[0]);38 }39 40 @Override41 protectedvoid addInAnimation(View[] aview) {42 43 }44 45 @Override46 protectedvoid addOutAnimation(View[] aview) {47 addAnimation(new ScaleAnimation(1F,0F, 1F, 0F, 1, 0.5F, 1, 0.5F));48 addAnimation(new AlphaAnimation(1F,0F));49 }50}接下来我们需要为这些控件做一下扩展,以便其可以再动画完成后显示或消失。
很简单:
View Row Code
1public class InOutImageButton extendsImageButton {2 3 privateAnimation animation;4 5 publicInOutImageButton(Context context,AttributeSet attrs, int defStyle) {6 super(context, attrs, defStyle);7 }8 9 publicInOutImageButton(Context context,AttributeSet attrs) {10 super(context, attrs);11 }12 13 publicInOutImageButton(Context context) {14 super(context);15 }16 17 @Override18 protectedvoid onAnimationEnd() {19 super.onAnimationEnd();20 if ((this.animationinstanceof InOutAnimation)) {21 setVisibility(((InOutAnimation) this.animation).direction !=InOutAnimation.Direction.OUT? View.VISIBLE22 :View.GONE);23 }24 }25 26 @Override27 protectedvoid onAnimationStart() {28 super.onAnimationStart();29 if ((this.animationinstanceof InOutAnimation))30 setVisibility(View.VISIBLE);31 }32 33 @Override34 publicvoid startAnimation(Animation animation) {35 super.startAnimation(animation);36 this.animation = animation;37 getRootView().postInvalidate();38 }39}那么到这里基本上就已经搞定了所有的事情了,剩下点没做的事就是把这些动画效果设置给对应的控件了,这里就不详细描述了。
源码下载:http://files.cnblogs.com/mudoot/PureComposerDemo.rar。