Android动画

前言

动画在应用中是非常常见的界面效果,同时也是提高用户体验的一种好手段。可是动画种类繁多,使用复杂,每当需要自定义动画实现复杂的动画效果时,自己总是显得束手无策。接下来就好好屡屡动画到底是怎样的。

一、动画的类型

视图动画:逐帧动画和补间动画    作用对象是:视图

属性动画:Android3.0之后的新特性

(1)补间动画:同一个图形通过视图在界面上进行透明度、缩放、平移、旋转的变化

          缩放:ScaleAnimation       放大、缩小视图的大小

          透明度:AlphaAnimation    改变视图的透明度

          旋转:RotateAnimation       旋转视图的透明度

          平移:TranslateAnimation    移动视图的位置

作用对象:视图控件,如TextView、Button,不可作用于view的属性如颜色、背景等

原理:通过确定开始的视图样式&结束的样式、中间动画变化过程由系统补全来确定一个动画

特点:使用简单、方便   缺点:仅控制整体实体效果,无法控制属性

应用场景:Activity、fragment的切换效果,视图中标准、基础的动画效果

具体使用:

Android提供了两种实现动画的方式

①xml配置的方式:动画描述的可读性更好

②纯编码的方式:动画效果可动态创建

设置方法:在xml代码中设置,res/anim/translate_animation.xml

<?xml version="1.0" encoding="utf-8"?>
<translate
    xmlns:android="http://schemas.android.com/apk/res/android"
// 以下参数是4种动画效果的公共属性,即都有的属性
    android:duration="3000" // 动画持续时间(ms),必须设置,动画才有效果
    android:startOffset ="1000" // 动画延迟开始时间(ms)
    android:fillBefore = “true” // 动画播放完后,视图是否会停留在动画开始的状态,默认为true
    android:fillAfter = “false” // 动画播放完后,视图是否会停留在动画结束的状态,优先于fillBefore值,默认为false
    android:fillEnabled= “true” // 是否应用fillBefore值,对fillAfter值无影响,默认为true
    android:repeatMode= “restart” // 选择重复播放动画模式,restart代表正序重放,reverse代表倒序回放,默认为restart|
    android:repeatCount = “0” // 重放次数(所以动画的播放次数=重放次数+1),为infinite时无限重复
    android:interpolator = @[package:]anim/interpolator_resource // 插值器,即影响动画的播放速度,下面会详细讲
    
    // 以下参数是平移动画特有的属性
    android:fromXDelta="0" // 视图在水平方向x 移动的起始值
    android:toXDelta="500" // 视图在水平方向x 移动的结束值

    android:fromYDelta="0" // 视图在竖直方向y 移动的起始值
    android:toYDelta="500" // 视图在竖直方向y 移动的结束值

    android:fromXDelta="0"
    android:toXDelta="500"
    android:fromYDelta="0"
    android:toYDelta="500"
    android:duration="1000">
</translate>

在Activity中引用xml动画,比如个ImageView设置动画:

public class AnimationActivity extends AppCompatActivity {
    private ImageView mIvImageView;
    private Button btn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_animation);
        mIvImageView = findViewById(R.id.iv_image);
        btn = findViewById(R.id.btn);
    }
    //button的点击事件
    public void startAnimation(View view){
        Animation animation = AnimationUtils.loadAnimation(this, R.anim.translate_animation);
        mIvImageView.startAnimation(animation);
    }
}

用Java代码实现同样的效果

public class AnimationActivity extends AppCompatActivity {
    private ImageView mIvImageView;
    private Button btn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_animation);
        mIvImageView = findViewById(R.id.iv_image);
        btn = findViewById(R.id.btn);
    }
    public void startAnimation(View view){
        Animation translateAnimation=new TranslateAnimation(0,500,0,500);
        // 1. fromXDelta :视图在水平方向x 移动的起始值
        // 2. toXDelta :视图在水平方向x 移动的结束值
        // 3. fromYDelta :视图在竖直方向y 移动的起始值
        // 4. toYDelta:视图在竖直方向y 移动的结束值
        translateAnimation.setDuration(1000);
        mIvImageView.startAnimation(translateAnimation);
    }
}

其他3种动画的设置方式也是一样的,就不一一举例了。但是看下其他动画的一些属性的意思

rotate旋转动画的一些属性

// 以下参数是旋转动画特有的属性
    android:duration="1000"
    android:fromDegrees="0" // 动画开始时 视图的旋转角度(正数 = 顺时针,负数 = 逆时针)
    android:toDegrees="270" // 动画结束时 视图的旋转角度(正数 = 顺时针,负数 = 逆时针)
    android:pivotX="50%" // 旋转轴点的x坐标
    android:pivotY="0" // 旋转轴点的y坐标
    // 轴点 = 视图缩放的中心点

// pivotX pivotY,可取值为数字,百分比,或者百分比p
    // 设置为数字时(如50),轴点为View的左上角的原点在x方向和y方向加上50px的点。在Java代码里面设置这个参数的对应参数是Animation.ABSOLUTE。
    // 设置为百分比时(如50%),轴点为View的左上角的原点在x方向加上自身宽度50%和y方向自身高度50%的点。在Java代码里面设置这个参数的对应参数是Animation.RELATIVE_TO_SELF。
    // 设置为百分比p时(如50%p),轴点为View的左上角的原点在x方向加上父控件宽度50%和y方向父控件高度50%的点。在Java代码里面设置这个参数的对应参数是Animation.RELATIVE_TO_PARENT
    // 两个50%表示动画从自身中间开始,具体如下图
    public void startAnimation(View view){
        // 参数说明:
        // 1. fromDegrees :动画开始时 视图的旋转角度(正数 = 顺时针,负数 = 逆时针)
        // 2. toDegrees :动画结束时 视图的旋转角度(正数 = 顺时针,负数 = 逆时针)
        // 3. pivotXType:旋转轴点的x坐标的模式
        // 4. pivotXValue:旋转轴点x坐标的相对值
        // 5. pivotYType:旋转轴点的y坐标的模式
        // 6. pivotYValue:旋转轴点y坐标的相对值

        // pivotXType = Animation.ABSOLUTE:旋转轴点的x坐标 =  View左上角的原点 在x方向 加上 pivotXValue数值的点(y方向同理)
        // pivotXType = Animation.RELATIVE_TO_SELF:旋转轴点的x坐标 = View左上角的原点 在x方向 加上 自身宽度乘上pivotXValue数值的值(y方向同理)
        // pivotXType = Animation.RELATIVE_TO_PARENT:旋转轴点的x坐标 = View左上角的原点 在x方向 加上 父控件宽度乘上pivotXValue数值的值 (y方向同理)
        
        Animation  rotateAnimation=new RotateAnimation(0,270,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
        rotateAnimation.setDuration(2000);
        mIvImageView.startAnimation(rotateAnimation);
    }

scale缩放动画:

// 以下参数是缩放动画特有的属性
    android:fromXScale="0.0" 
    // 动画在水平方向X的起始缩放倍数
    // 0.0表示收缩到没有;1.0表示正常无伸缩
    // 值小于1.0表示收缩;值大于1.0表示放大

    android:toXScale="2"  //动画在水平方向X的结束缩放倍数

    android:fromYScale="0.0" //动画开始前在竖直方向Y的起始缩放倍数
    android:toYScale="2" //动画在竖直方向Y的结束缩放倍数

    android:pivotX="50%" // 缩放轴点的x坐标
    android:pivotY="50%" // 缩放轴点的y坐标
    // 轴点 = 视图缩放的中心点

    // pivotX pivotY,可取值为数字,百分比,或者百分比p
    // 设置为数字时(如50),轴点为View的左上角的原点在x方向和y方向加上50px的点。在Java代码里面设置这个参数的对应参数是Animation.ABSOLUTE。
    // 设置为百分比时(如50%),轴点为View的左上角的原点在x方向加上自身宽度50%和y方向自身高度50%的点。在Java代码里面设置这个参数的对应参数是Animation.RELATIVE_TO_SELF。
    // 设置为百分比p时(如50%p),轴点为View的左上角的原点在x方向加上父控件宽度50%和y方向父控件高度50%的点。在Java代码里面设置这个参数的对应参数是Animation.RELATIVE_TO_PARENT
  public void startAnimation(View view){
        // 参数说明:
        // 1. fromX :动画在水平方向X的结束缩放倍数
        // 2. toX :动画在水平方向X的结束缩放倍数
        // 3. fromY :动画开始前在竖直方向Y的起始缩放倍数
        // 4. toY:动画在竖直方向Y的结束缩放倍数
        // 5. pivotXType:缩放轴点的x坐标的模式
        // 6. pivotXValue:缩放轴点x坐标的相对值
        // 7. pivotYType:缩放轴点的y坐标的模式
        // 8. pivotYValue:缩放轴点y坐标的相对值

        // pivotXType = Animation.ABSOLUTE:缩放轴点的x坐标 =  View左上角的原点 在x方向 加上 pivotXValue数值的点(y方向同理)
        // pivotXType = Animation.RELATIVE_TO_SELF:缩放轴点的x坐标 = View左上角的原点 在x方向 加上 自身宽度乘上pivotXValue数值的值(y方向同理)
        // pivotXType = Animation.RELATIVE_TO_PARENT:缩放轴点的x坐标 = View左上角的原点 在x方向 加上 父控件宽度乘上pivotXValue数值的值 (y方向同理)

        Animation scaleAnimation=new ScaleAnimation(0,3,0,3,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
        scaleAnimation.setDuration(3000);
        mIvImageView.startAnimation(scaleAnimation);
    }

透明度Alpha动画

  // 以下参数是透明度动画特有的属性
    android:fromAlpha="1.0" // 动画开始时视图的透明度(取值范围: -1 ~ 1)
    android:toAlpha="0.0"// 动画结束时视图的透明度(取值范围: -1 ~ 1)
    public void startAnimation(View view){
        // 参数说明:
        // 1. fromAlpha:动画开始时视图的透明度(取值范围: -1 ~ 1)
        // 2. toAlpha:动画结束时视图的透明度(取值范围: -1 ~ 1)  1:代表完全显示,0时就是完全消失
        Animation alphaAnimation=new AlphaAnimation(1,0);
        alphaAnimation.setDuration(5000);
        mIvImageView.startAnimation(alphaAnimation);
    }

(2)逐帧动画:在界面的同一个位置上不断切换显示不同的图片

作用对象:视图控件,如TextView、Button,不可作用于view的属性如颜色、背景等

原理:将动画拆分成帧的形式,且定义每一帧=每一张图片,按顺序播放预先准备好的图片

特点:简单、方便,缺点:容易引起OOM,因为会用大量尺寸较大的图片资源

应用场景:较为复杂的个性化动画效果

举例:帧动画需要在drawable目录下创建xml

<?xml version="1.0" encoding="utf-8"?>
<animation-list
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true">
    <item android:drawable="@mipmap/loading_000" android:duration="100"/>
    <item android:drawable="@mipmap/loading_002" android:duration="100"/>
    <item android:drawable="@mipmap/loading_004" android:duration="100"/>
    <item android:drawable="@mipmap/loading_006" android:duration="100"/>
    <item android:drawable="@mipmap/loading_008" android:duration="100"/>
    <item android:drawable="@mipmap/loading_010" android:duration="100"/>
    <item android:drawable="@mipmap/loading_012" android:duration="100"/>
    <item android:drawable="@mipmap/loading_014" android:duration="100"/>
    <item android:drawable="@mipmap/loading_016" android:duration="100"/>
    <item android:drawable="@mipmap/loading_018" android:duration="100"/>
    <item android:drawable="@mipmap/loading_020" android:duration="100"/>
    <item android:drawable="@mipmap/loading_022" android:duration="100"/>
    <item android:drawable="@mipmap/loading_024" android:duration="100"/>
    <item android:drawable="@mipmap/loading_026" android:duration="100"/>
    <item android:drawable="@mipmap/loading_028" android:duration="100"/>
    <item android:drawable="@mipmap/loading_030" android:duration="100"/>
    <item android:drawable="@mipmap/loading_032" android:duration="100"/>
    <item android:drawable="@mipmap/loading_034" android:duration="100"/>
    <item android:drawable="@mipmap/loading_036" android:duration="100"/>
    <item android:drawable="@mipmap/loading_040" android:duration="100"/>
    <item android:drawable="@mipmap/loading_042" android:duration="100"/>
    <item android:drawable="@mipmap/loading_044" android:duration="100"/>
    <item android:drawable="@mipmap/loading_046" android:duration="100"/>
    <item android:drawable="@mipmap/loading_048" android:duration="100"/>
    <item android:drawable="@mipmap/loading_050" android:duration="100"/>
</animation-list>

在Activity中引用

public class AnimationActivity extends AppCompatActivity {
    private ImageView mIvImageView;
    private Button mBtnStartAnimation;
    private Button mBtnStopAnimation;
    private AnimationDrawable mAnimationDrable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_animation);
        mIvImageView = findViewById(R.id.iv_image);
        mBtnStartAnimation = findViewById(R.id.btn);
        mBtnStopAnimation = findViewById(R.id.stop_animation);
    }

    public void startAnimation(View view) {
      mIvImageView.setImageResource(R.drawable.frame_animation);
        //开始动画
      mAnimationDrable= (AnimationDrawable) mIvImageView.getDrawable();
      mAnimationDrable.start();

    }

    public void stopAnimation(View view) {
        mIvImageView.setImageResource(R.drawable.frame_animation);
        //开始动画
        mAnimationDrable= (AnimationDrawable) mIvImageView.getDrawable();
        mAnimationDrable.stop();
    }

}

方式二:使用Java代码


public class AnimationActivity extends AppCompatActivity {
    private ImageView mIvImageView;
    private Button mBtnStartAnimation;
    private Button mBtnStopAnimation;
    private AnimationDrawable mAnimationDrable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_animation);
        mIvImageView = findViewById(R.id.iv_image);
        mBtnStartAnimation = findViewById(R.id.btn);
        mBtnStopAnimation = findViewById(R.id.stop_animation);
        mAnimationDrable = new AnimationDrawable();
        for (int i = 0; i <= 25; i++) {
            //如果是放在mipmap下的,将第二个参数换成是mipmap就可以了
            int id = getResources().getIdentifier("a" + i, "drawable", getPackageName());
            Drawable drawable = getResources().getDrawable(id);
            mAnimationDrable.addFrame(drawable, 100);
        }

    }

    public void startAnimation(View view) {
        mAnimationDrable.setOneShot(true);
        mIvImageView.setImageDrawable(mAnimationDrable);
     
        mAnimationDrable.stop();
        // 特别注意:在动画start()之前要先stop(),不然在第一次动画之后会停在最后一帧,这样动画就只会触发一次
        mAnimationDrable.start();
    }

    public void stopAnimation(View view) {
        //开始动画
        mAnimationDrable.setOneShot(true);
        mIvImageView.setImageDrawable(mAnimationDrable);
        mAnimationDrable.stop();
    }

}

特别注意图片命名的格式:顺序要挨着,最好不要出现下划线之类的,命名的越简单获取的时候的越简单

好了至此补间动画和逐帧动画就演示完了!

三、复合动画(AnimationSet)

复合动画就是多个单一动画组合在一起。

AnimatorSet.play(Animator anim)   :播放当前动画
AnimatorSet.after(long delay)   :将现有动画延迟x毫秒后执行
AnimatorSet.with(Animator anim)   :将现有动画和传入的动画同时执行
AnimatorSet.after(Animator anim)   :将现有动画插入到传入的动画之后执行
AnimatorSet.before(Animator anim) :  将现有动画插入到传入的动画之前执行

xml配置文件实现组合动画

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha
        android:duration="2000"
        android:fromAlpha="0"
        android:toAlpha="1"></alpha>

    <rotate
        android:duration="2000"
        android:fromDegrees="0"
        android:toDegrees="360"></rotate>
    <!--"Xml复合动画: 透明度从透明到不透明, 持续2s, 接着进行旋转360度的动画, 持续2s"-->
</set>

在Activity中引用:

package com.example.wcystart.otherproject;

import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.ImageView;

public class AnimationActivity extends AppCompatActivity {
    private ImageView mIvImageView;
    private Button mBtnStartAnimation;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_animation);
        mIvImageView = findViewById(R.id.iv_image);
        mBtnStartAnimation = findViewById(R.id.btn);
   }

    public void startAnimation(View view) {
        Animation animationSet = AnimationUtils.loadAnimation(this,R.anim.combine_animation);
        animationSet.setDuration(2000);
        mIvImageView.startAnimation(animationSet);

    }
}

使用Java代码实现复合动画:


public class AnimationActivity extends AppCompatActivity {
    private ImageView mIvImageView;
    private Button mBtnStartAnimation;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_animation);
        mIvImageView = findViewById(R.id.iv_image);
        mBtnStartAnimation = findViewById(R.id.btn);
    }

    public void startAnimation(View view) {
        AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
        alphaAnimation.setDuration(1000);
        RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        rotateAnimation.setDuration(1000);
        //合并到复合动画中
        AnimationSet animationSet = new AnimationSet(false);
        animationSet.addAnimation(alphaAnimation);
        animationSet.addAnimation(rotateAnimation);
        mIvImageView.startAnimation(animationSet);
    }
}

四、动画监听器

Animation.addListener(new AnimatorListener() {
          @Override
          public void onAnimationStart(Animation animation) {
              //动画开始时执行
          }
      
           @Override
          public void onAnimationRepeat(Animation animation) {
              //动画重复时执行
          }

         @Override
          public void onAnimationCancel()(Animation animation) {
              //动画取消时执行
          }
    
          @Override
          public void onAnimationEnd(Animation animation) {
              //动画结束时执行
          }
      });

因Animator类包括(ValueAnimator类(又包括ObjectAnimator类)和AnimatorSet类),所以他们几个都可设置addListener

使用动画适配器可实现监听4个方法中的某一个,

animator.addListener(new AnimatorListenerAdapter() {  

    @Override  
    public void onAnimationStart(Animator animation) {  
    // 如想只想监听动画开始时刻,就只需要单独重写该方法就可以
    }  
});

四、属性动画(重点学习)

学习链接:Android属性动画

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值