实现Path2.0中绚丽的的旋转菜单
2015-03-30 15:06
309 查看
实现Path2.0中绚丽的的旋转菜单 - MudooT - 博客园
最近真的是忙死了,做了很久的这个菜单动画特效,都没有时间写博客,今天在机场等飞机终于有了空闲时间。
上图先:
那么下面开始吧~
首先,将整个菜单动画分解开来。
1. 一级菜单按钮的旋转动画2个,十字和叉叉状态的转换。
2. 二级菜单按钮的平移动画2个,弹簧效果的in和out
3. 二级菜单按钮的点击效果,放大消失,其他未点击按钮缩小消失。
4. 一级菜单按钮的恢复效果,放大出现
好的 逐一去实现:
首先是一级菜单按钮的旋转动画,这2个动画可以直接在xml中定义,然后load到代码中来,具体代码如下:
rotate_story_add_button_in.xml
1 <?xml version="1.0" encoding="UTF-8"?>
2 <rotate
3 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%"
android:fillAfter="true"
android:fillEnabled="true"
/>
rotate_story_add_button_out.xml
1 <?xml version="1.0" encoding="UTF-8"?>
2 <rotate
3 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%"
android:fillAfter="true"
android:fillEnabled="true"
/>
这2段没什么好说的,定义好角度即可。
接下来是需要我们在代码中定义的动画部分,这几个动画的部分需要定义一个基类,作为统一的调用接口,这个基类被称作InOutAnimation,继承自AnimationSet,这个基类的主要工作是为view提供in和out两种不同的状态时的动画效果。其子类需要实现2个方法:
protected abstract void addInAnimation(View aview[]);
protected abstract void addOutAnimation(View aview[]); 从而进行view的入场和离场动画。
下面是InOutAnimation的代码部分:
1 public abstract class InOutAnimation extends AnimationSet {
2
3 public Direction direction;
4
5 public enum Direction {
6 IN, OUT;
7 }
8
9 public InOutAnimation(Direction direction, long l, View[] aview) {
super(true);
this.direction = direction;
switch (this.direction) {
case IN:
addInAnimation(aview);
break;
case OUT:
addOutAnimation(aview);
break;
}
setDuration(l);
}
protected abstract void addInAnimation(View aview[]);
protected abstract void addOutAnimation(View aview[]);
}
接下来就是重头戏啦,二级菜单按钮的平移动画。
这部分动画看起来可能会比较复杂和神秘,其实不然,当把整个动画过程分解开来的时候,都是最最简单的平移而已,我们要做的只是定义一下平移的起点和终点、开始动画的顺序以及插值(Interpolator),让整个过程看起来很炫。
先说动画的起点和终点吧,起点很简单,就是整个view的左下角,即0,0点,为了效果漂亮一些,我们稍微的将左下角位置定义的有一些偏移,经验上的值是16,-13,这个点的位置看你心情而定咯~ 好 终点就是你想让他在的点上就好了,终点我们将定义到layout中去,为这个2级菜单指定一个margin的值就好。
还是上代码比较直观:
动画如下:
收缩部分:TranslateAnimation(xOffset + -mlp.leftMargin, 0F,yOffset + mlp.bottomMargin, 0F)
扩张部分:TranslateAnimation(0F, xOffset + -mlp.leftMargin, 0F,yOffset + mlp.bottomMargin)位置定义部分:
例如:
android:layout_marginBottom="142dp" android:layout_marginLeft="10.667dp"
这个位置大家可以直观的在布局文件中看到,详细的布局文件也将在下面展示。
以上是单独的每一个二级按钮的动画,而组合的动画就是指定了一下开始的时间差以及插值:
这个就是奥妙所在了,OvershootInterpolator AnticipateInterpolator 这2个插值器提供了弹力效果。
整段的代码如下:
ComposerButtonAnimation.java
1 public class ComposerButtonAnimation extends InOutAnimation {
2
3 public static final int DURATION = 500;
4 private static final int xOffset = 16;
5 private static final int yOffset = -13;
6
7 public ComposerButtonAnimation(Direction direction, long l, View view) {
8 super(direction, l, new View[] { view });
9 }
public static void startAnimations(ViewGroup viewgroup,
InOutAnimation.Direction direction) {
switch (direction) {
case IN:
startAnimationsIn(viewgroup);
break;
case OUT:
startAnimationsOut(viewgroup);
break;
}
}
private static void startAnimationsIn(ViewGroup viewgroup) {
for (int i = 0; i < viewgroup.getChildCount(); i++) {
if (viewgroup.getChildAt(i) instanceof InOutImageButton) {
InOutImageButton inoutimagebutton = (InOutImageButton) viewgroup
.getChildAt(i);
ComposerButtonAnimation animation = new ComposerButtonAnimation(
InOutAnimation.Direction.IN, DURATION, inoutimagebutton);
animation.setStartOffset((i * 100)
/ (-1 + viewgroup.getChildCount()));
animation.setInterpolator(new OvershootInterpolator(2F));
inoutimagebutton.startAnimation(animation);
}
}
}
private static void startAnimationsOut(ViewGroup viewgroup) {
for (int i = 0; i < viewgroup.getChildCount(); i++) {
if (viewgroup.getChildAt(i) instanceof InOutImageButton) {
InOutImageButton inoutimagebutton = (InOutImageButton) viewgroup
.getChildAt(i);
ComposerButtonAnimation animation = new ComposerButtonAnimation(
InOutAnimation.Direction.OUT, DURATION,
inoutimagebutton);
animation.setStartOffset((100 * ((-1 + viewgroup
.getChildCount()) - i))
/ (-1 + viewgroup.getChildCount()));
animation.setInterpolator(new AnticipateInterpolator(2F));
inoutimagebutton.startAnimation(animation);
}
}
}
@Override
protected void addInAnimation(View[] aview) {
MarginLayoutParams mlp = (MarginLayoutParams) aview[0]
.getLayoutParams();
addAnimation(new TranslateAnimation(xOffset + -mlp.leftMargin, 0F,
yOffset + mlp.bottomMargin, 0F));
}
@Override
protected void addOutAnimation(View[] aview) {
MarginLayoutParams mlp = (MarginLayoutParams) aview[0]
.getLayoutParams();
addAnimation(new TranslateAnimation(0F, xOffset + -mlp.leftMargin, 0F,
yOffset + mlp.bottomMargin));
}
}
剩下的增大出现、增大消失及缩小消失都是scale和alpha的组合动画
例如增大出现为:
addAnimation(new ScaleAnimation(0F, 1F, 0F, 1F, 1, 0.5F, 1, 0.5F));
addAnimation(new AlphaAnimation(0F, 1F)); 整段的代码如下:
1 public class ComposerButtonGrowAnimationIn extends InOutAnimation {
2
3 public ComposerButtonGrowAnimationIn(int i) {
4 super(InOutAnimation.Direction.IN, i, new View[0]);
5 }
6
7 @Override
8 protected void addInAnimation(View[] aview) {
9 addAnimation(new ScaleAnimation(0F, 1F, 0F, 1F, 1, 0.5F, 1, 0.5F));
addAnimation(new AlphaAnimation(0F, 1F));
}
@Override
protected void addOutAnimation(View[] aview) {}
}
public class ComposerButtonGrowAnimationOut extends InOutAnimation {
public ComposerButtonGrowAnimationOut(int i) {
super(InOutAnimation.Direction.OUT, i, new View[0]);
}
@Override
protected void addInAnimation(View[] aview) {}
@Override
protected void addOutAnimation(View[] aview) {
addAnimation(new ScaleAnimation(1F, 5F, 1F, 5F, 1, 0.5F, 1, 0.5F));
addAnimation(new AlphaAnimation(1F, 0F));
}
} public class ComposerButtonShrinkAnimationOut extends InOutAnimation {
public ComposerButtonShrinkAnimationOut(int i) {
super(InOutAnimation.Direction.OUT, i, new View[0]);
}
@Override
protected void addInAnimation(View[] aview) {
}
@Override
protected void addOutAnimation(View[] aview) {
addAnimation(new ScaleAnimation(1F, 0F, 1F, 0F, 1, 0.5F, 1, 0.5F));
addAnimation(new AlphaAnimation(1F, 0F));
}
}
接下来我们需要为这些控件做一下扩展,以便其可以再动画完成后显示或消失。
很简单
1 public class InOutImageButton extends ImageButton {
2
3 private Animation animation;
4
5 public InOutImageButton(Context context, AttributeSet attrs, int defStyle) {
6 super(context, attrs, defStyle);
7 }
8
9 public InOutImageButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public InOutImageButton(Context context) {
super(context);
}
@Override
protected void onAnimationEnd() {
super.onAnimationEnd();
if ((this.animation instanceof InOutAnimation)) {
setVisibility(((InOutAnimation) this.animation).direction != InOutAnimation.Direction.OUT ? View.VISIBLE
: View.GONE);
}
}
@Override
protected void onAnimationStart() {
super.onAnimationStart();
if ((this.animation instanceof InOutAnimation))
setVisibility(View.VISIBLE);
}
@Override
public void startAnimation(Animation animation) {
super.startAnimation(animation);
this.animation = animation;
getRootView().postInvalidate();
}
}
那么到这里基本上就已经搞定了所有的事情了,剩下点没做的事就是把这些动画效果设置给对应的控件了,这里就不详细描述了,大家有兴趣可以直接下载源码来搞一下啦~
上图先:
那么下面开始吧~
首先,将整个菜单动画分解开来。
1. 一级菜单按钮的旋转动画2个,十字和叉叉状态的转换。
2. 二级菜单按钮的平移动画2个,弹簧效果的in和out
3. 二级菜单按钮的点击效果,放大消失,其他未点击按钮缩小消失。
4. 一级菜单按钮的恢复效果,放大出现
好的 逐一去实现:
首先是一级菜单按钮的旋转动画,这2个动画可以直接在xml中定义,然后load到代码中来,具体代码如下:
rotate_story_add_button_in.xml
1 <?xml version="1.0" encoding="UTF-8"?>
2 <rotate
3 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%"
android:fillAfter="true"
android:fillEnabled="true"
/>
rotate_story_add_button_out.xml
1 <?xml version="1.0" encoding="UTF-8"?>
2 <rotate
3 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%"
android:fillAfter="true"
android:fillEnabled="true"
/>
这2段没什么好说的,定义好角度即可。
接下来是需要我们在代码中定义的动画部分,这几个动画的部分需要定义一个基类,作为统一的调用接口,这个基类被称作InOutAnimation,继承自AnimationSet,这个基类的主要工作是为view提供in和out两种不同的状态时的动画效果。其子类需要实现2个方法:
protected abstract void addInAnimation(View aview[]);
protected abstract void addOutAnimation(View aview[]); 从而进行view的入场和离场动画。
下面是InOutAnimation的代码部分:
1 public abstract class InOutAnimation extends AnimationSet {
2
3 public Direction direction;
4
5 public enum Direction {
6 IN, OUT;
7 }
8
9 public InOutAnimation(Direction direction, long l, View[] aview) {
super(true);
this.direction = direction;
switch (this.direction) {
case IN:
addInAnimation(aview);
break;
case OUT:
addOutAnimation(aview);
break;
}
setDuration(l);
}
protected abstract void addInAnimation(View aview[]);
protected abstract void addOutAnimation(View aview[]);
}
接下来就是重头戏啦,二级菜单按钮的平移动画。
这部分动画看起来可能会比较复杂和神秘,其实不然,当把整个动画过程分解开来的时候,都是最最简单的平移而已,我们要做的只是定义一下平移的起点和终点、开始动画的顺序以及插值(Interpolator),让整个过程看起来很炫。
先说动画的起点和终点吧,起点很简单,就是整个view的左下角,即0,0点,为了效果漂亮一些,我们稍微的将左下角位置定义的有一些偏移,经验上的值是16,-13,这个点的位置看你心情而定咯~ 好 终点就是你想让他在的点上就好了,终点我们将定义到layout中去,为这个2级菜单指定一个margin的值就好。
还是上代码比较直观:
动画如下:
收缩部分:TranslateAnimation(xOffset + -mlp.leftMargin, 0F,yOffset + mlp.bottomMargin, 0F)
扩张部分:TranslateAnimation(0F, xOffset + -mlp.leftMargin, 0F,yOffset + mlp.bottomMargin)位置定义部分:
例如:
android:layout_marginBottom="142dp" android:layout_marginLeft="10.667dp"
这个位置大家可以直观的在布局文件中看到,详细的布局文件也将在下面展示。
以上是单独的每一个二级按钮的动画,而组合的动画就是指定了一下开始的时间差以及插值:
这个就是奥妙所在了,OvershootInterpolator AnticipateInterpolator 这2个插值器提供了弹力效果。
整段的代码如下:
ComposerButtonAnimation.java
1 public class ComposerButtonAnimation extends InOutAnimation {
2
3 public static final int DURATION = 500;
4 private static final int xOffset = 16;
5 private static final int yOffset = -13;
6
7 public ComposerButtonAnimation(Direction direction, long l, View view) {
8 super(direction, l, new View[] { view });
9 }
public static void startAnimations(ViewGroup viewgroup,
InOutAnimation.Direction direction) {
switch (direction) {
case IN:
startAnimationsIn(viewgroup);
break;
case OUT:
startAnimationsOut(viewgroup);
break;
}
}
private static void startAnimationsIn(ViewGroup viewgroup) {
for (int i = 0; i < viewgroup.getChildCount(); i++) {
if (viewgroup.getChildAt(i) instanceof InOutImageButton) {
InOutImageButton inoutimagebutton = (InOutImageButton) viewgroup
.getChildAt(i);
ComposerButtonAnimation animation = new ComposerButtonAnimation(
InOutAnimation.Direction.IN, DURATION, inoutimagebutton);
animation.setStartOffset((i * 100)
/ (-1 + viewgroup.getChildCount()));
animation.setInterpolator(new OvershootInterpolator(2F));
inoutimagebutton.startAnimation(animation);
}
}
}
private static void startAnimationsOut(ViewGroup viewgroup) {
for (int i = 0; i < viewgroup.getChildCount(); i++) {
if (viewgroup.getChildAt(i) instanceof InOutImageButton) {
InOutImageButton inoutimagebutton = (InOutImageButton) viewgroup
.getChildAt(i);
ComposerButtonAnimation animation = new ComposerButtonAnimation(
InOutAnimation.Direction.OUT, DURATION,
inoutimagebutton);
animation.setStartOffset((100 * ((-1 + viewgroup
.getChildCount()) - i))
/ (-1 + viewgroup.getChildCount()));
animation.setInterpolator(new AnticipateInterpolator(2F));
inoutimagebutton.startAnimation(animation);
}
}
}
@Override
protected void addInAnimation(View[] aview) {
MarginLayoutParams mlp = (MarginLayoutParams) aview[0]
.getLayoutParams();
addAnimation(new TranslateAnimation(xOffset + -mlp.leftMargin, 0F,
yOffset + mlp.bottomMargin, 0F));
}
@Override
protected void addOutAnimation(View[] aview) {
MarginLayoutParams mlp = (MarginLayoutParams) aview[0]
.getLayoutParams();
addAnimation(new TranslateAnimation(0F, xOffset + -mlp.leftMargin, 0F,
yOffset + mlp.bottomMargin));
}
}
剩下的增大出现、增大消失及缩小消失都是scale和alpha的组合动画
例如增大出现为:
addAnimation(new ScaleAnimation(0F, 1F, 0F, 1F, 1, 0.5F, 1, 0.5F));
addAnimation(new AlphaAnimation(0F, 1F)); 整段的代码如下:
1 public class ComposerButtonGrowAnimationIn extends InOutAnimation {
2
3 public ComposerButtonGrowAnimationIn(int i) {
4 super(InOutAnimation.Direction.IN, i, new View[0]);
5 }
6
7 @Override
8 protected void addInAnimation(View[] aview) {
9 addAnimation(new ScaleAnimation(0F, 1F, 0F, 1F, 1, 0.5F, 1, 0.5F));
addAnimation(new AlphaAnimation(0F, 1F));
}
@Override
protected void addOutAnimation(View[] aview) {}
}
public class ComposerButtonGrowAnimationOut extends InOutAnimation {
public ComposerButtonGrowAnimationOut(int i) {
super(InOutAnimation.Direction.OUT, i, new View[0]);
}
@Override
protected void addInAnimation(View[] aview) {}
@Override
protected void addOutAnimation(View[] aview) {
addAnimation(new ScaleAnimation(1F, 5F, 1F, 5F, 1, 0.5F, 1, 0.5F));
addAnimation(new AlphaAnimation(1F, 0F));
}
} public class ComposerButtonShrinkAnimationOut extends InOutAnimation {
public ComposerButtonShrinkAnimationOut(int i) {
super(InOutAnimation.Direction.OUT, i, new View[0]);
}
@Override
protected void addInAnimation(View[] aview) {
}
@Override
protected void addOutAnimation(View[] aview) {
addAnimation(new ScaleAnimation(1F, 0F, 1F, 0F, 1, 0.5F, 1, 0.5F));
addAnimation(new AlphaAnimation(1F, 0F));
}
}
接下来我们需要为这些控件做一下扩展,以便其可以再动画完成后显示或消失。
很简单
1 public class InOutImageButton extends ImageButton {
2
3 private Animation animation;
4
5 public InOutImageButton(Context context, AttributeSet attrs, int defStyle) {
6 super(context, attrs, defStyle);
7 }
8
9 public InOutImageButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public InOutImageButton(Context context) {
super(context);
}
@Override
protected void onAnimationEnd() {
super.onAnimationEnd();
if ((this.animation instanceof InOutAnimation)) {
setVisibility(((InOutAnimation) this.animation).direction != InOutAnimation.Direction.OUT ? View.VISIBLE
: View.GONE);
}
}
@Override
protected void onAnimationStart() {
super.onAnimationStart();
if ((this.animation instanceof InOutAnimation))
setVisibility(View.VISIBLE);
}
@Override
public void startAnimation(Animation animation) {
super.startAnimation(animation);
this.animation = animation;
getRootView().postInvalidate();
}
}
那么到这里基本上就已经搞定了所有的事情了,剩下点没做的事就是把这些动画效果设置给对应的控件了,这里就不详细描述了,大家有兴趣可以直接下载源码来搞一下啦~
相关文章推荐
- 实现Path2.0中绚丽的的旋转菜单
- Android 实现Path2.0中绚丽的的旋转菜单
- Android实现Path2.0中绚丽的的旋转菜单
- 实现Path2.0中绚丽的的旋转菜单
- 实现Path2.0中绚丽的的旋转菜单
- 实现Path2.0中绚丽的的旋转菜单
- Path2.0中绚丽的的旋转菜单
- iOS开发资源:几个类似Path 2.0侧滑菜单的效果实现
- jQuery Wheel Menu:实现漂亮的 Path 风格旋转菜单
- 开源项目推荐(2):Android SlidingMenu 实现类似与Path2.0和Facebook滑动菜单
- SlidingMenu和ActionBarSherlock结合做出出色的App布局,Facebook 和 Path 2.0 滑动式菜单都可以实现(android页面布局效果)
- iOS开发资源:几个类似Path 2.0侧滑菜单的效果实现
- jQuery Wheel Menu:实现漂亮的 Path 风格旋转菜单
- SlidingMenu和ActionBarSherlock结合做出出色的App布局,Facebook 和 Path 2.0 滑动式菜单都可以实现(android页面布局效果)
- Android 高仿【优酷】圆盘旋转菜单 的实现
- Android 高仿【优酷】圆盘旋转菜单的实现
- AvalonDock 2.0+Caliburn.Micro+MahApps.Metro实现Metro风格插件式系统(菜单篇)
- Android 高仿【优酷】圆盘旋转菜单的实现(转载)
- 移动旋转菜单的实现方案
- unity3d实现菜单旋转效果