欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android动画基础

程序员文章站 2022-03-01 20:52:27
...

Android动画基础

课程目标:

1. 了解定义逐帧动画的方法

2. 掌握定义视图动画的方法

3. 掌握定义属性动画的方法

 

学习内容:

1. 逐帧动画

2. 视图动画系统

3. 属性动画系统  *

 

一、 逐帧动画:

Android中我们可以通过AnimationDrawable 这个对象来定义逐帧动画。我们可以通过在xml文件中定义 <animation-list> 来共同完成逐帧动画。

原理: 它操作的对象是一张张图片,通过将一张张图片循环播放,然后形成动画。

实践:

1. 在drawable目录下创建一个xml文件:

<?xml version="1.0" encoding="utf-8"?>

<animation-list android:oneshot="true"

    xmlns:android="http://schemas.android.com/apk/res/android">

    <item

        android:drawable="@drawable/frame_1"

        android:duration="100" />



    <item

        android:drawable="@drawable/frame_2"

        android:duration="100" />



    <item

        android:drawable="@drawable/frame_3"

        android:duration="100" />

</animation-list>

注释: 每一个item就是一帧图片,duration 代表的是显示时间。上面这个xml文件就是一个AnimationDrawable对象。android:oneshot属性是让动画只播放一遍。

2.java代码

public class FrameAnimationActivity extends AppCompatActivity {



    private AnimationDrawable animationDrawable;



    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_frame_animation);



        View view = findViewById(R.id.view);

        animationDrawable = (AnimationDrawable) view.getBackground();

        // 让动画只播放一遍就结束,默认是循环播放。

        animationDrawable.setOneShot(true);

    }



    public void onClick(View view) {

        switch (view.getId()) {

            case R.id.btnStart:

                // 开始播放

                animationDrawable.start();

                break;

            case R.id.btnStop:

                // 结束播放

                animationDrawable.stop();

                break;

        }

    }

}

3.xml布局文件:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:id="@+id/activity_frame_animation"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:paddingBottom="@dimen/activity_vertical_margin"

    android:paddingLeft="@dimen/activity_horizontal_margin"

    android:paddingRight="@dimen/activity_horizontal_margin"

    android:paddingTop="@dimen/activity_vertical_margin"

    tools:context="com.animation.frame.FrameAnimationActivity">



    <View

        android:id="@+id/view"

        android:background="@drawable/loading"

        android:layout_centerInParent="true"

        android:layout_width="300dp"

        android:layout_height="300dp" />



    <LinearLayout

        android:layout_alignParentBottom="true"

        android:orientation="horizontal"

        android:layout_width="match_parent"

        android:layout_height="wrap_content">



        <Button

            android:id="@+id/btnStart"

            android:text="Start"

            android:onClick="onClick"

            android:layout_width="0dp"

            android:layout_weight="1"

            android:layout_height="wrap_content" />



        <Button

            android:id="@+id/btnStop"

            android:text="Stop"

            android:onClick="onClick"

            android:layout_width="0dp"

            android:layout_weight="1"

            android:layout_height="wrap_content" />

    </LinearLayout>



</RelativeLayout>

以上就是逐帧动画的全部内容。

 

二、 视图动画系统

它操作的是Android中的视图对象。也就是说我们可以通过视图动画系统可以让视图对象(如:TextView、 Button、ImageView等)动起来。

视图动画系统相关的类定义在 android.view.animation 包中,这个包里有个Animation 抽象类,我们可以通过Animation 的实现类: AlphaAnimation、ScaleAnimation、TranslateAnimation、RotateAnimation、AnimationSet等通过补间动画(补间动画:简单理解就是对一个视图对象,给定一个起始点,一个终点然后在一定的时间完成相应的动画)完成视图动画。

 

1.AlphaAnimation(透明度动画)

我们有两种方式完成: 1. 通过xml文件  2. 通过java代码

如果通过xml文件,我们可以将根标签设为<alpha>,这样的一个xml文件就对应一个AlphaAnimation对象。

 

2.ScaleAnimation(缩放动画)

我们有两种方式完成: 1. 通过xml文件  2. 通过java代码

如果通过xml文件,我们可以将根标签设为<scale>,这样的一个xml文件就对应一个ScaleAnimation对象。对一个视图对象在x轴或者y轴进行缩放。

 

3.TranslateAnimation(平移动画)

我们有两种方式完成: 1. 通过xml文件  2. 通过java代码

如果通过xml文件,我们可以将根标签设为<translate>,这样的一个xml文件就对应一个TranslateAnimation对象。对一个视图对象在x轴或者y轴进行平移。

 

4.RotateAnimation(平移动画)

我们有两种方式完成: 1. 通过xml文件  2. 通过java代码

如果通过xml文件,我们可以将根标签设为<rotate>,这样的一个xml文件就对应一个RotateAnimation对象。对一个视图对象在x轴或者y轴进行旋转。

 

5.AnimationSet(集合动画)

我们有两种方式完成: 1. 通过xml文件  2. 通过java代码

如果通过xml文件,我们可以将根标签设为<set>,这样的一个xml文件就对应一个AnimationSet对象。对视图同时执行上面的动画。

 

6.Interpolator(视图动画之插值器)

通过插值器可以定义我们视图动画的变化率,一般可以通过贝塞尔曲线来完成。

 

实践:

1.在/res目录下新建一个目录/res/anim,然后再创建一个/res/anim/alpha.xml文件(透明度动画):

​
<?xml version="1.0" encoding="utf-8"?>

<set xmlns:android="http://schemas.android.com/apk/res/android">



    <alpha

        android:duration="1000"

        <!-- 浮点数,起始透明度,1.0代表不透明, 0.0代表完全透明 -->

        android:fromAlpha="1.0"

        <!-- 终点透明度 -->

        android:toAlpha="0.1" />



</set>

/res/anim/scale.xml文件(缩放动画)

​
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000">

    <scale
        android:fromXScale="1.0"
        android:fromYScale="1.0"
        android:pivotX="50%"
        android:pivotY="50%"
        <!-- x轴扩大2倍 -->
        android:toXScale="2.0"
               <!--  y轴不变 -->
        android:toYScale="1.0" />

    <!-- pivotX和pivotY是缩放的基准点,默认是视图的原点,也就是左上角, %就是相对于视图本身的比例, %p是相对于视图父控件的长度比例。  android:fillAfter属性是动画保持停止后状态,默认false。 -->

</set>

/res/anim/tranlate.xml文件(平移动画)

​
<?xml version="1.0" encoding="utf-8"?>

<set xmlns:android="http://schemas.android.com/apk/res/android"

    android:fillAfter="true">

    <translate

        android:duration="@android:integer/config_shortAnimTime"

        android:fromXDelta="0"

        android:fromYDelta="0"

        android:toXDelta="80%p"

        android:toYDelta="0" />

</set>

/res/anim/rotate.xml文件(旋转动画)

<?xml version="1.0" encoding="utf-8"?>

<set xmlns:android="http://schemas.android.com/apk/res/android"

    android:fillAfter="true">



    <rotate

        android:fromDegrees="0"

        android:duration="300"

        android:toDegrees="360"

        android:pivotX="50%"

        android:pivotY="50%"

        android:repeatCount="infinite"

        />

        <!-- android:repeatCount重复播放次数,infinite表示无限循环; android:repeatMode: restart 表示从起始位置重复播放, reverse表示重复播放时原路返回播放。-->



</set>

/res/anim/set.xml文件(集合动画)

<?xml version="1.0" encoding="utf-8"?>

<set xmlns:android="http://schemas.android.com/apk/res/android">



    <rotate

        android:duration="1000"

        android:fromDegrees="0"

        android:toDegrees="720"

        android:pivotX="50%"

        android:pivotY="50%"

        />



    <translate

        android:duration="1000"

        android:startOffset="1000"

        android:fromXDelta="0"

        android:toXDelta="500"

        android:fromYDelta="0"

        android:toYDelta="0"

        />

    <!-- android:startOffset 等待多长时间开始这个动画。 -->    

</set>

 

2.java代码:

public class ViewAnimationActivity extends AppCompatActivity {



    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_view_animation);

    }



    @Override

    public boolean onCreateOptionsMenu(Menu menu) {

        getMenuInflater().inflate(R.menu.renew, menu);

        return super.onCreateOptionsMenu(menu);

    }



    @Override

    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {

            case R.id.renew:

                // 重建activity

                recreate();

                break;

        }

        return super.onOptionsItemSelected(item);

    }



    public void onClick(View view) {

        switch (view.getId()) {

            case R.id.viewAlphaAnimation:

                // 视图动画之透明度动画

                Animation alphaAnimation = AnimationUtils.loadAnimation(this, R.anim.alpha);

                view.startAnimation(alphaAnimation);

                break;

            case R.id.viewScaleAnimation:

                 //  视图动画之缩放动画

                Animation scaleAnimation = AnimationUtils.loadAnimation(this, R.anim.scale);

                view.startAnimation(scaleAnimation);

                break;

            case R.id.viewTranslateAnimation:

                 //  视图动画之平移动画

                Animation translateAnimation = AnimationUtils.loadAnimation(this, R.anim.translate);

                view.startAnimation(translateAnimation);

                break;

            case R.id.viewRotateAnimation:

                //  视图动画之旋转动画

                Animation rotateAnimation = AnimationUtils.loadAnimation(this, R.anim.rotate);

                view.startAnimation(rotateAnimation);

                break;

            case R.id.viewSetAnimation:

                // 集合动画

                Animation setAnimation = AnimationUtils.loadAnimation(this, R.anim.set);

                view.startAnimation(setAnimation);

                break;

            case R.id.viewLinear:

            case R.id.viewAccelerate:

                // 视图动画之插值器

                View viewLinear = findViewById(R.id.viewLinear);

                View viewAccelerate = findViewById(R.id.viewAccelerate);



                Animation animationLinear = AnimationUtils.loadAnimation(this, R.anim.translate);

                Animation animationAccelerate = AnimationUtils.loadAnimation(this, R.anim.translate);

                // 线性插值器

                animationLinear.setInterpolator(new LinearInterpolator());

                // 加速插值器

                animationAccelerate.setInterpolator(new AccelerateInterpolator());



                viewLinear.startAnimation(animationLinear);

                viewAccelerate.startAnimation(animationAccelerate);



                break;

        }

    }

}

3.布局xml文件:

<?xml version="1.0" encoding="utf-8"?>

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:id="@+id/activity_view_animation"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:paddingBottom="@dimen/activity_vertical_margin"

    android:paddingLeft="@dimen/activity_horizontal_margin"

    android:paddingRight="@dimen/activity_horizontal_margin"

    android:paddingTop="@dimen/activity_vertical_margin"

    tools:context="com.animation.view.ViewAnimationActivity">



    <LinearLayout

        android:background="@drawable/edge"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:orientation="vertical">



        <View

            android:id="@+id/viewAccelerate"

            android:background="@color/colorPrimary"

            android:layout_margin="8dp"

            android:layout_width="50dp"

            android:onClick="onClick"

            android:layout_height="50dp"/>



        <View

            android:id="@+id/viewLinear"

            android:alpha="0.5"

            android:background="@color/colorPrimary"

            android:layout_margin="8dp"

            android:layout_width="50dp"

            android:onClick="onClick"

            android:layout_height="50dp"/>



        <TextView

            android:id="@+id/viewAlphaAnimation"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:onClick="onClick"

            android:text="Alpha"

            style="@style/AnimationTextView" />



        <TextView

            android:id="@+id/viewScaleAnimation"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_gravity="center_horizontal"

            android:onClick="onClick"

            android:text="Scale"

            style="@style/AnimationTextView" />



        <TextView

            android:id="@+id/viewTranslateAnimation"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:onClick="onClick"

            android:text="Translate"

            style="@style/AnimationTextView" />



        <TextView

            android:id="@+id/viewRotateAnimation"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:onClick="onClick"

            android:text="Rotate"

            android:layout_gravity="center_horizontal"

            style="@style/AnimationTextView" />



        <TextView

            android:id="@+id/viewSetAnimation"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:onClick="onClick"

            android:text="Set"

            style="@style/AnimationTextView" />



        <View

            android:layout_width="match_parent"

            android:layout_height="200dp" />



    </LinearLayout>

</ScrollView>

/res/values/style.xml文件:

<resources>

    <!-- Base application theme. -->

    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">

        <!-- Customize your theme here. -->

        <item name="colorPrimary">@color/colorPrimary</item>

        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>

        <item name="colorAccent">@color/colorAccent</item>

    </style>



    <style name="AnimationTextView">

        <item name="android:background">@color/colorPrimary</item>

        <item name="android:padding">16dp</item>

        <item name="android:layout_margin">8dp</item>

        <item name="android:textAppearance">@style/TextAppearance.AppCompat.Large</item>

        <item name="android:textColor">@android:color/white</item>

    </style>



</resources>

/res/drawable/edge.xml

<?xml version="1.0" encoding="utf-8"?>

<shape xmlns:android="http://schemas.android.com/apk/res/android">



    <solid android:color="@android:color/transparent" />



    <stroke

        android:width="1px"

        android:color="@android:color/black" />



</shape>

三、属性动画

原理: 在相应的时间内通过不断的改变对象属性值的方式形成动画。这个属性的值有一个起始值和一个结束值,然后Animator对象就可以驱动完成这个过渡的过程,形成动画效果,所以Animator对象就是属性动画的驱动器。

属性动画相关的类都在android.animation包中,这个包中的抽象类Animator 就是属性动画相关的类,ValueAnimator就是抽象类Animator的实现类。

 

视图动画 VS 属性动画:

1. 操作对象

视图动画只能操作视图对象,但是属性动画可以操作任意对象。

2. 属性

视图动画呈现变化的只是效果,并不能改变视图对象实际的属性;但是属性动画不仅可以呈现

出动画效果还能改变对象真正的属性。视图动画所能完成的属性动画也都能完成,但是属性动

画能完成的,视图动画很多却不能做到,所以综合来说属性动画更为强大。

 

属性动画可以定义的动画属性:

1. 动画的时长

2. 时间插值器(动画完成时间的变化率)

3. 重复次数以及重复模式

4. 动画集(就是几种动画效果的集合)

5. 延迟(延迟多久开始执行动画)

 

ValueAnimator能够改变属性的值,但是我们并不能指定改变哪个对象的属性值。ObjectAnimator就能够指定我们能够改变哪个对象的属性值,它是valueAnimator的子类。和视图动画一样,我们可以在xml文件中指定ObjectValue对象,也可以通过java代码来指定。如果在xml文件中指定,根标签为<objectAnimator>,每个objectAnimator标签对应一个ObjectAnimator对象。在属性动画中我们通过AnimatorInflater工具类来从资源文件中加载属性动画。

 

虽然属性动画可以让任何对象都可以产生动画,但是大多数情况下我们都是让View视图产生动画效果,为此,Android中为我们实现View视图动画,专门提供了ViewPropertyAnimator类。使用方法:

a. 通过view.animate()方法获取一个ViewPropertyAnimator 对象。

b. 再调用要改变的相应的属性值,然后调用start() 方法即可产生动画效果。

eg: view.animate().translationX(500f).setDuration(1000).start();

 

1.在xml中定义改变透明度的objectAnimator对象:

在res/目录下新建一个animator目录: res/animator/alpha.xml

<?xml version="1.0" encoding="utf-8"?>

<set xmlns:android="http://schemas.android.com/apk/res/android">



    <objectAnimator

        android:propertyName="alpha"   <!-- 改变的属性值,一定要确保目标对象中有这个属性值的set方法,否则无效 -->

        android:duration="1000"

        android:valueType="floatType"

        android:valueFrom="1.0"

        android:valueTo="0.1"

        />



</set>

实践;

1.java代码:

public class PropertyActivity extends AppCompatActivity {



    private static final String TAG = "PropertyActivity";



    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_property);

    }



    public void onClick(View view) {

        switch (view.getId()) {

//            case R.id.btnValueAnimator:

//                ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 1.0f);

                  // 属性动画的时间插值器

//                valueAnimator.setInterpolator(new LinearInterpolator());

//                valueAnimator.setDuration(100);

                  // 属性动画的监听器(监听属性动画完成的过程)

//                valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

//                    @Override

//                    public void onAnimationUpdate(ValueAnimator animation) {

                          // 属性动画中属性值的完成度

//                        float animatedFraction = animation.getAnimatedFraction();

                          // 属性动画中属性值的具体值

//                        float animatedValue = (float) animation.getAnimatedValue();

//                        Log.d(TAG, "onAnimationUpdate: " + String.format("%.3f  %.3f", animatedFraction, animatedValue));

//                    }

//                });

//                valueAnimator.start();

//                break;

            case R.id.viewAlphaAnimation:

                // 通过xml文件定义ObjectAnimator对象,改变这个对象的透明度

                Animator alphaAnimator = AnimatorInflater.loadAnimator(this, R.animator.alpha);

                // 设置目标对象

                alphaAnimator.setTarget(view);

                alphaAnimator.start();

                break;

            case R.id.viewScaleAnimation:

                // 通过java代码使目标对象view产生缩放动画

                ObjectAnimator.ofFloat(view, "scaleX", 1.0f, 3.0f).start();

                break;

            case R.id.viewTranslateAnimation:

                // 通过ViewPropertyAnimator 对象产生视图对象的平移属性的动画效果

                view.animate().translationX(500f).setDuration(1000).start();

                break;

            case R.id.viewRotateAnimation:

                             //  通过ViewPropertyAnimator 对象产生视图对象的翻转属性的动画效果

                view.animate().rotation(720).start();

                break;

            case R.id.viewSetAnimation:

                                 // 实现属性动画集合(两种方法)

                                 //  方法一:  通过AnimatorSet 对象实现属性动画集合

//                Animator rotateAnimator = ObjectAnimator.ofFloat(view, "rotation", 0, 720);

//                rotateAnimator.setDuration(1000);

//

//                Animator moveAnimator = ObjectAnimator.ofFloat(view, "x", 0, 500);

//                moveAnimator.setDuration(1000);

//

//                AnimatorSet set = new AnimatorSet();

                  // 同时实现翻转和平移动画    

//                set.playTogether(rotateAnimator, moveAnimator);

                  // 顺序完成属性动画,先翻转再平移

//                set.playSequentially(rotateAnimator, moveAnimator);

//                set.start();



                // 方法二: 通过 ViewPropertyAnimator 对象实现属性动画集合效果

                view.animate().rotation(720).setDuration(1000).start();

                view.animate().translationX(500).setDuration(1000).setStartDelay(1000).start();



                break;

        }

    }



}

 

 

 

 

 

 

 

相关标签: Android动画