视图动画(补间动画+逐帧动画)

视图动画

✨执行XML中的动画

Animation animationScale = AnimationUtils.loadAnimation(this, R.anim.scale_one);
view.startAnimation(animationScale)

✨动画Animation属性

  • android:duration:一次动画持续时间(单位毫秒)
  • android:fillAfter:true:保持动画结束时的状态
  • android:fillBefore:true:动画结束时还原到初始化状态
  • android:fillEnabled:同fillBefore
  • android:repeatCount:指定动画重复次数,当取值为infinite时,表示无限循环。
  • android:repeatMode:用于设定重复的类型,有reverse和restart两个值。reverse表示倒序回放,restart表示重放,必须与repeatCount一起使用才能看到效果。
  • android:interpolator:插值器,其实就是指定的动画效果。

1、取消动画
void cancel()
2、将控件重置到动画开始前状态
void reset()
3、设置动画监听
setAnimationListener(Animation.AnimationListener listener);
回调函数如下:

  • onAnimationEnd():当动画结束时调用;
  • onAnimationRepeat():当动画重复时调用;
  • onAnimationStart():当动画开始时调用;

一、scale(渐变尺寸伸缩动画效果)

  • android:fromXScale:动画起始时,控件在X轴方向上相对自身的缩放比例,浮点值。(1.0表示自身无变化,0.5代表缩小1倍,2.0代表放大1倍)
  • android:toXScale:动画结束时,控件在X轴方向上相对自身的缩放比例,浮点值。
  • android:fromYScale:动画起始时,控件在Y轴方向上相对自身的缩放比例,浮点值。
  • android:toYScale:动画结束时,控件在Y轴方向上相对自身的缩放比例,浮点值。
  • android:pivotX:缩放起始点X轴坐标,可以是数值、百分数、百分数p三种方式,如50、50%、50%p。如果是数值,则表示在当前视图的左上角,即原点处加上50px,作为缩放起始点X轴坐标;如果是50%,则表示在当前控件的左上角加上自己宽度的50%作为缩放起始点X轴坐标;如果是50%p,则表示在当前控件的左上角加上父控件宽度的50%作为缩放起点X轴坐标。
  • android:pivotY:缩放起始点Y轴坐标,取值及含义与android:pivotX相同。

示例代码:

<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"
    android:fromXScale="0.1"
    android:fromYScale="0.1"
    android:toXScale="1.5"
    android:toYScale="1.5"
    android:pivotX="50"
    android:pivotY="50">
</scale>

代码的方式:
只要是第三个构造函数:其中pivotXType和pivotYType有以下三个取值:①、Animation.ABSOLUTE(对应的是数值),②、Animation.RELATIVE_TO_SELF(对应的是百分数),③、Animation.RELATIVE_TO_PARENT(对应的是百分数p)。

ScaleAnimation(float fromX,float toX,float fromY,float toY);
ScaleAnimation(float fromX,float toX,float fromY,float toY,float pivoteX,float pivoteY);
ScaleAnimation(float fromX,float toX,float fromY,float toY,int pivotXType,float pivotXValue,int pivotYType,float pivotYValue);

代码示例

ScaleAnimation scaleAnim = new ScaleAnimation(0.0f,1.4f,0.0f,1.4f,Animation.RELATION_TO_SELF,0.5f,Animation.RELATION_TO_SELF,0.5f);
scaleAnim.setDuration(1000);
view.startAnimation(scaleAnim);

当pivotX和pivotY的数值(不是百分值)较大时,动画效果是边平移边缩放的效果。当fromXScale和fromYScale的值不是从零开始的话,pivotX和pivotY的作用就被遮盖了,可能是起始点变化比起始缩放的效果早一些执行导致的(我也很奇怪)。还有当pivotX和pivotY有值且为正值时,view会从右王左开始缩放(至于为什么我想和Matrix的具体计算有关吧,待详细了解)。

二、alpha(实现渐变透明度动画效果)

  • android:fromAlpha:开始时的透明度,取值范围0.0~1.0,0.0表示全透明,1.0表示完全不透明。
  • android:toAlpha:动画结束时的透明度,取值范围0.0~1.0,0.0表示全透明,1.0表示完全不透明。

示例代码:

<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"
    android:fromAlpha="0"
    android:toAlpha="1">
</alpha>
AlphaAnimation(float fromAlpha,float toAlpha);
AlphaAnimation alphaAnim = new AlphaAnimation(1.0f,0.1f);

三、rotate(实现画面转移旋转动画效果)

  • android:fromDegrees:动画开始旋转时的角度位置,正值代表顺时针方向的度数,负值代表逆时针方向的度数。
  • android:toDegrees:动画结束时旋转到的角度位置,正值代表顺时针方向的度数,负值代表逆时针方向的度数。
    -android:pivotX:旋转中心点X轴坐标,默认旋转中心点是控件坐标原点。可以是数值、百分数、百分数p三种样式,比如50、50%、50%p,具体含义同之前所讲。
  • android:pivotY:旋转中心点Y轴坐标,具体同上。

示例代码:

<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"
    android:fillAfter="true"
    android:fromDegrees="0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toDegrees="360"></rotate>

构造函数

RotateAnimation(float fromDegree,float toDegree);
RotateAnimation(float fromDegree,float toDegree,float pivotX,float
pivoY);
RotateAnimation(float fromDegree,float toDegree,int pivotXType,float pivotXValue,int pivotYType,float
pivoYValue);

代码示例:

RotateAnimation rotateAnim=new RotateAnimation(0,-650,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);

四、translate(实现画面变化位置移动动画效果)

  • android:fromXDelta:起始点X轴坐标,可以是数值、百分数、百分数p三种样式,作用同之前所讲。
  • android:fromYDelta:起始点Y轴坐标,可以是数值、百分数、百分数p三种样式,作用同之前所讲。
  • android:toXDelta:终点X轴坐标。
  • android:toYDelta:终点Y轴坐标。

示例代码:

<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"
    android:fillAfter="false"
    android:fromXDelta="0"
    android:fromYDelta="0"
    android:toXDelta="80"
    android:toYDelta="80"></translate>

构造函数

TranslateAnimation(float fromXDelta,float toXDelta,float fromYDelta,float toYDelta);
TranslateAnimation(int fromXType,float fromXValue,int toXType,float toXValue,int fromYType,float fromYValue,int toYType,float toYValue);

代码示例

TranslateAnimation translateAnim = new TranslateAnimation(Animation.ABSOLUTE,0,Animation.ABSOLUTE,-80,Animation.ABSOLUTE,0,Animation.ABSOLUTE,-80);

五、set标签(定义动画集)

<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"
    android:fillAfter="true">
    <alpha
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />

    <scale
        android:fromXScale="0.0"
        android:fromYScale="0.0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="1"
        android:toYScale="1" />

    <rotate
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="720" />
</set>

构造函数:其中shareInterpolator 参数的取值有true和false。当为true时,用于在AnimationSet类中定义一个插值器(Interpolator),其下面的所有动画共用该插值器;当为false时,则其下的动画定义各自的插值器。

AnimationSet(Context context , AttributeSet attrs);
AnimationSet(boolean shareInterpolator);

示例代码:

Animation alphaAnim = new AlphaAnimation(1.0f,1.0f);
Animation scalAnim=new ScaleAnimation(0.0f,1.4f,0.0f,1.4f,Animation.RELATION_TO_SELF,0.5f,Animation.RELATION_TO_SELF,0.5f);
Animation rotateAnim=new RotateAnimation(0,720,Animation.RELATION_TO_SELF,0.5f,Animation.RELATION_TO_SELF,0.5f);
AnimationSet setAnim = new AnimationSet(true);
setAnim.addAnimation(alphaAnim);
setAnim.addAnimation(scalAnim);
setAnim.addAnimation(rotateAnim);
setAnim.setDuration(3000);
setAnim.setFillAfter(true);
view.startAnimation(setAnim);

注意:在set标签中设置repeateCount属性是无效的,必须对每个动画单独设置才有作用。

逐帧动画

逐帧动画就是一帧挨着一帧的播放图片,就像放电影一样,既可以通过XML代码实现也可以通过Java代码实现。

一、XML实现

1、定义xml动画文件

将xml定义在/res下的anim或drawable目录中,代码如下:

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">

    <item
        android:drawable="@mipmap/spinner_0"
        android:duration="60" />
    <item
        android:drawable="@mipmap/spinner_1"
        android:duration="60" />
    <item
        android:drawable="@mipmap/spinner_2"
        android:duration="60" />
    <item
        android:drawable="@mipmap/spinner_3"
        android:duration="60" />
    <item
        android:drawable="@mipmap/spinner_4"
        android:duration="60" />
    <item
        android:drawable="@mipmap/spinner_5"
        android:duration="60" />
    <item
        android:drawable="@mipmap/spinner_6"
        android:duration="60" />
    <item
        android:drawable="@mipmap/spinner_7"
        android:duration="60" />
    <item
        android:drawable="@mipmap/spinner_8"
        android:duration="60" />
    <item
        android:drawable="@mipmap/spinner_9"
        android:duration="60" />
    <item
        android:drawable="@mipmap/spinner_10"
        android:duration="60" />
    <item
        android:drawable="@mipmap/spinner_11"
        android:duration="60" />
</animation-list>
  • 元素是必须的,并且必须作为根元素,可以包含一个或多个元素;
  • android:oneshot如果为true,那么动画只执行一次;如果定义为false,则一直循环。
  • android:drawable:指定此帧动画对应的图片资源。
  • android:duration:代表此帧动画持续的时间,是一个整数,单位毫秒。

2、设置ImageView

给ImageView设置动画资源,可以通过android:src 实现,也可以通过android:background实现。

3、AnimationDrawable开始动画

最后在代码中开始动画。代码展示:

//通过android:src方式设置后的获取方式
AnimationDrawable anim =(AnimationDrawable) image.getDrawable();
//通过android:background方式设置后的获取方式
AnimationDrawable anim =(AnimationDrawable) image.getBackground();
anim.start();

3、AnimationDrawable类

  • void start():开始播放逐帧动画。
  • void stop():停止播放逐帧动画。
  • int getDuration(int index):得到指定index的帧的持续时间。
  • Drawable getFrame(int index):得到指定index的帧所对应的Drawable对象。
  • int getNumberOfFrames():得到当前所有帧数量。
  • boolean isRunning():判断当前AnimationDrawable是否正在播放。
  • void setOneShot(boolean oneShot):设置AnimationDrawable是否执行一次,true代表执行一次,false代表循环执行。
  • boolean isOneShot():判断当前AnimationDrawable是否执行一次。
  • void addFrame(Drawable frame,int duration):为AnimationDrawable添加1帧,并设置持续时间。

二、代码实现

代码实现:

final AnimationDrawable anim = new AnimationDrawable();
for(int i=1;i<14;i++){
  int id=getResources().getIdentifier("spinner_"+i,"mipmap",getPackageName());
  Drawable drawable = getResources().getDrawable(id);
  anim.addFrame(drawable,60);
}
anim.setOneShot(false);
image.setBackgroundDrawable(anim);
anim.start();

这段代码的难点是通过文件名拿到文件:

int getIdentifier(String name , String defType , String defPackage);
  • String name: 所要查找资源ID的资源名称。
  • String defType:资源所在的文件类型。
  • String defPackage: 应用包名。

推荐阅读更多精彩内容