Android动画基础
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动画基础 -- 帧动画
下一篇: Android之基础动画