Android为我们提供了2中动画
一: Tween Animation 渐变动画 通过对特定对象做图像的变换,例如: 平移, 缩放,旋转, 淡入淡出 等。
二: Frame Animation 帧动画 创建一个淡入阿瓦不了可以按照指定的时间间隔一个一个显示。顺序播放
下面我们就详细介绍一下这两中动画:
首先我们介绍 渐变动画:
1. Tween Animation
1. 渐变动画有四种样式:
alpha: 渐变透明度
scale: 缩放尺寸伸缩动画
translate: 移动动画效果
rotate : 旋转动画
2.使用方式:
2.1 可以通过xml资源文件设置, 然后通过AnimationUtils的LoadAnimation方法加载
举例:
alpha: 渐变透明度
<alpha android:interpolator= “@android:anim/accelerate_decelerate_interpolator”
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:duration="3000"
></alpha>
<!--
interpolator:指定一个动画的插入器,用来控制动画的速度变化
fromAlpha:动画起始时透明度
0.0表示完全透明
1.0表示完全不透明
以上值取0.0-1.0之间的float数据类型的数字
toAlpha:动画结束时透明度
duration:持续时间 -->
scale: 缩放尺寸伸缩动画
<scale
android:interpolator= “@android:anim/accelerate_decelerate_interpolator”
android:fromXScale=”0.0″
android:toXScale=”1.4″
android:fromYScale=”0.0″
android:toYScale=”1.4″
android:pivotX=”50%”
android:pivotY=”50%”
android:fillAfter=”false”
android:startOffset=“700”
android:duration=”700″
android:repeatCount=”10″ />
<!--
fromXScale[float]:为动画起始时,X坐标上的伸缩尺寸,0.0表示收缩到没有
fromYScale[float]:为动画起始时,Y坐标上的伸缩尺寸,0.0表示收缩到没有
1.0表示正常无伸缩
值小于1.0表示收缩
值大于1.0表示放大
toXScale[float]:为动画结束时,X坐标上的伸缩尺寸
toYScale[float]:为动画结束时,X坐标上的伸缩尺寸
pivotX[float]:为动画相对于物件的X坐标的开始位置
pivotY[float]:为动画相对于物件的X、Y坐标的开始位置
50,50%,50%p。这三种写法就分别代表了ABSOLUTE,RELATIVE_TO_SELF和RELATIVE_TO_PARENT。
属性值说明:从0%-100%中取值,50%为物件的X或Y方向坐标上的中点位置
fillAfter[boolean]:当设置为true ,该动画转化在动画结束后被应用
startOffset[long]:动画之间的时间间隔,从上次动画停多少时间开始执行下个动画
repeatCount[int]:动画的重复次数 -->
<translate
android:interpolator=”@android:anim/accelerate_decelerate_interpolator”
android:fromXDelta=”30″
android:toXDelta=”-80″
android:fromYDelta=”30″
android:toYDelta=”300″
android:duration=”2000″ />
t;!--
fromXDelta:为动画起始时 X坐标上的位置
toXDelta: 为动画结束时 X坐标上的位置
fromYDelta: 为动画起始时 Y坐标上的位置
toYDelta:为动画结束时 Y坐标上的位置 -->
rotate : 旋转动画
<rotate
android:interpolator=”@android:anim/accelerate_decelerate_interpolator”
android:fromDegrees=”0″
android:toDegrees=”+350″
android:pivotX=”50%”
android:pivotY=”50%”
android:duration=”3000″ />
t;!--
fromDegrees:动画起始时物件的角度
toDegrees:动画结束时物件旋转的角度 可以大于360度
当角度为负数——表示逆时针旋转
当角度为正数——表示顺时针旋转
(负数from——to正数:顺时针旋转)
(负数from——to负数:逆时针旋转)
(正数from——to正数:顺时针旋转)
(正数from——to负数:逆时针旋转)
pivotX;:为动画相对于物件的X、Y坐标的开始位置
pivotY: 为动画相对于物件的X、Y坐标的开始位置
50%为物件的X或Y方向坐标上的中点位置 -->
2.2 使用 Anmation的相关子类构造函数来初始化animation对象。
在android的sdk中提供了想要的类,animation类派生出了 aplhaAnimation ScaleAnimation TranslateAnimation RotateAnimation 分别实现了平移,旋转,渐变,尺寸,和透明度等动画
举例:
//在代码中定义 动画实例对象
private Animation myAnimation_Alpha;
private Animation myAnimation_Scale;
private Animation myAnimation_Translate;
private Animation myAnimation_Rotate;
//根据各自的构造方法来初始化一个实例对象
myAnimation_Alpha = new AlphaAnimation(0.1f, 1.0f);
myAnimation_Scale = new ScaleAnimation(0.0f, 1.4f, 0.0f, 1.4f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
myAnimation_Translate = new TranslateAnimation(30.0f, -80.0f, 30.0f, 300.0f);
myAnimation_Rotate = new RotateAnimation(0.0f, +350.0f,
Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF, 0.5f);
1. AlphaAnimation
AlphaAnimation类对象定义
1. private AlphaAnimation myAnimation_Alpha;
AlphaAnimation类对象构造
AlphaAnimation(float fromAlpha, float toAlpha)
//第一个参数fromAlpha为 动画开始时候透明度
//第二个参数toAlpha为 动画结束时候透明度
myAnimation_Alpha = new AlphaAnimation(0.1f, 1.0f);
//说明:
// 0.0表示完全透明
// 1.0表示完全不透明
设置动画持续时间
myAnimation_Alpha.setDuration(5000);
//设置时间持续时间为 5000毫秒
2. ScaleAnimation
ScaleAnimation类对象定义
private ScaleAnimation myAnimation_Scale;
ScaleAnimation类对象构造
ScaleAnimation(float fromX, float toX, float fromY, float toY,
int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)
//第一个参数fromX为动画起始时 X坐标上的伸缩尺寸
//第二个参数toX为动画结束时 X坐标上的伸缩尺寸
//第三个参数fromY为动画起始时Y坐标上的伸缩尺寸
//第四个参数toY为动画结束时Y坐标上的伸缩尺寸
/*说明:
以上四种属性值
0.0表示收缩到没有
1.0表示正常无伸缩
值小于1.0表示收缩
值大于1.0表示放大
*/
//第五个参数pivotXType为动画在X轴相对于物件位置类型
//第六个参数pivotXValue为动画相对于物件的X坐标的开始位置
//第七个参数pivotXType为动画在Y轴相对于物件位置类型
//第八个参数pivotYValue为动画相对于物件的Y坐标的开始位置
myAnimation_Scale = new ScaleAnimation(0.0f, 1.4f, 0.0f, 1.4f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
设置动画持续时间
myAnimation_Scale.setDuration(700);
//设置时间持续时间为 700毫秒
3. TranslateAnimation
ranslateAnimation类对象定义
private TranslateAnimation myAnimation_Translate;
TranslateAnimation类对象构造
TranslateAnimation(float fromXDelta, float toXDelta,
float fromYDelta, float toYDelta)
//第一个参数fromXDelta为动画起始时 X坐标上的移动位置
//第二个参数toXDelta为动画结束时 X坐标上的移动位置
//第三个参数fromYDelta为动画起始时Y坐标上的移动位置
//第四个参数toYDelta为动画结束时Y坐标上的移动位置
设置动画持续时间
myAnimation_Translate = new TranslateAnimation(10f, 100f, 10f, 100f);
myAnimation_Translate.setDuration(2000);
//设置时间持续时间为 2000毫秒
4. RotateAnimation
RotateAnimation类对象定义
private RotateAnimation myAnimation_Rotate;
RotateAnimation类对象构造
RotateAnimation(float fromDegrees, float toDegrees,
int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)
//第一个参数fromDegrees为动画起始时的旋转角度
//第二个参数toDegrees为动画旋转到的角度
//第三个参数pivotXType为动画在X轴相对于物件位置类型
//第四个参数pivotXValue为动画相对于物件的X坐标的开始位置
//第五个参数pivotXType为动画在Y轴相对于物件位置类型
//第六个参数pivotYValue为动画相对于物件的Y坐标的开始位置
myAnimation_Rotate = new RotateAnimation(0.0f, +350.0f,
Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF, 0.5f);
设置动画持续时间
myAnimation_Rotate.setDuration(3000);
//设置时间持续时间为 3000毫秒
如何Java代码中使用动画效果
使用从View父类继承过来的方法startAnimation()来为View或是子类View等等添加一个动画效果
public void startAnimation (Animation animation)
view.startAnimation(myAnimation_Alpha);
view.startAnimation(myAnimation_Scale);
view.startAnimation(myAnimation_Translate);
view.startAnimation(myAnimation_Rotate);
3: android sdk通过Interpolator 控制动画的运行
首先要了解为什么需要插值器,因为在补间动画中,我们一般只定义关键帧(首帧或尾帧),然后由系统自动生成中间帧,生成中间帧的这个过程可以成为“插值”。插值器定义了动画变化的速率,提供不同的函数定义变化值相对于时间的变化规则,可以定义各种各样的非线性变化函数,比如加速、减速等。下面是几种常见的插值器:
Interpolator对象 | 资源ID | 功能作用 |
---|---|---|
AccelerateDecelerateInterpolator | @android:anim/accelerate_decelerate_interpolator | 先加速再减速 |
AccelerateInterpolator | @android:anim/accelerate_interpolator | 加速 |
AnticipateInterpolator | @android:anim/anticipate_interpolator | 先回退一小步然后加速前进 |
AnticipateOvershootInterpolator | @android:anim/anticipate_overshoot_interpolator | 在上一个基础上超出终点一小步再回到终点 |
BounceInterpolator | @android:anim/bounce_interpolator | 最后阶段弹球效果 |
CycleInterpolator | @android:anim/cycle_interpolator | 周期运动 |
DecelerateInterpolator | @android:anim/decelerate_interpolator | 减速 |
LinearInterpolator | @android:anim/linear_interpolator | 匀速 |
OvershootInterpolator | @android:anim/overshoot_interpolator | 快速到达终点并超出一小步最后回到终点 |
<set android:interpolator="@android:anim/accelerate_interpolator">
...
</set>
<alpha android:interpolator="@android:anim/accelerate_interpolator"
.../>
<accelerateDecelerateInterpolator> 无
<accelerateInterpolator> android:factor 浮点值,加速速率,默认为1
<anticipateInterploator> android:tension 浮点值,起始点后退的张力、拉力数,默认为2
<anticipateOvershootInterpolator> android:tension 同上 android:extraTension 浮点值,拉力的倍数,默认为1.5(2 * 1.5)
<bounceInterpolator> 无
<cycleInterplolator> android:cycles 整数值,循环的个数,默认为1
<decelerateInterpolator> android:factor 浮点值,减速的速率,默认为1
<linearInterpolator> 无
<overshootInterpolator> 浮点值,超出终点后的张力、拉力,默认为2
下面我们就拿最后一个插值器来举例:
<?xml version="1.0" encoding="utf-8"?>
<overshootInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:tension="7.0"/>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/my_overshoot_interpolator"
.../>
我们可以实现Interpolator接口,因为上面所有的Interpolator都实现了Interpolator接口,这个接口定义了一个方法:float getInterpolation(float input);
此方法由系统调用,input代表动画的时间,在0和1之间,也就是开始和结束之间。
线性(匀速)插值器定义如下:
public float getInterpolation(float input) {
return input;
}
加速减速插值器定义如下:
public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
有兴趣的话,大家可以尝试一下自定义一个插值器。
应用:
先来介绍一下旋转动画的使用,布局文件/res/layout/rotate.xml如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FFFFFF">
<ImageView
android:id="@+id/piechart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="@drawable/piechart"/>
<Button
android:id="@+id/positive"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="顺时针"
android:onClick="positive"/>
<Button
android:id="@+id/negative"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="逆时针"
android:onClick="negative"/>
</LinearLayout>
我们定义了一个ImageView,用于显示一个饼状图,演示旋转动画,然后定义了两个按钮,用以运行编码实现的动画。动画定义文件/res/anim/rotate.xml如下:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator">
<rotate
android:fromDegrees="0"
android:toDegrees="+360"
android:pivotX="50%"
android:pivotY="50%"
android:duration="5000"/>
</set>
最后再来看一下RotateActivity.java代码:
public class RotateActivity extends Activity {
private int currAngle;
private View piechart;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.rotate);
piechart = findViewById(R.id.piechart);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.rotate);
piechart.startAnimation(animation);
}
public void positive(View v) {
Animation anim = new RotateAnimation(currAngle, currAngle + 180, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
/** 匀速插值器 */
LinearInterpolator lir = new LinearInterpolator();
anim.setInterpolator(lir);
anim.setDuration(1000);
/** 动画完成后不恢复原状 */
anim.setFillAfter(true);
currAngle += 180;
if (currAngle > 360) {
currAngle = currAngle - 360;
}
piechart.startAnimation(anim);
}
public void negative(View v) {
Animation anim = new RotateAnimation(currAngle, currAngle - 180, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
/** 匀速插值器 */
LinearInterpolator lir = new LinearInterpolator();
anim.setInterpolator(lir);
anim.setDuration(1000);
/** 动画完成后不恢复原状 */
anim.setFillAfter(true);
currAngle -= 180;
if (currAngle < -360) {
currAngle = currAngle + 360;
}
piechart.startAnimation(anim);
}
}
4.动画的运行
模式
独占模式; 即程序主线程进入循环,根据动画指令不断刷新屏幕,直至动画结束
终端模式: 即有单独一个线程时间计数,每隔一定的时间向主线程发送通知,主线程接到通知后更新屏幕。
二:Frame Animation 动画:
android通过AnimationDrawable来定义
可以在xml定义,也可以使用AnimationDrawable中的API定义,由于Tween Animation与Frame Aniamtion
有着很大的不同,因此xml定义的格式也不一样,首先是 animation-list根节点,animation-list根节点中包含多个item子节点,每个item节点定义一帧动画,当前帧的drawable资源和当前帧持续的时间
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot=["true" | "false"] >
<item
android:drawable="@[package:]drawable/drawable_resource_name"
android:duration="integer" />
</animation-list>
需要注意的是:
<animation-list>元素是必须的,并且必须要作为根元素,可以包含一或多个<item>元素;android:onshot如果定义为true的话,此动画只会执行一次,如果为false则一直循环。
<item>元素代表一帧动画,android:drawable指定此帧动画所对应的图片资源,android:druation代表此帧持续的时间,整数,单位为毫秒。
我们新建一个名为anim的工程,将四张连续的图片分别命名为f1.png,f2.png,f3.png,f4.png,放于drawable目录,然后新建一个frame.xml文件:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@drawable/f1" android:duration="300" />
<item android:drawable="@drawable/f2" android:duration="300" />
<item android:drawable="@drawable/f3" android:duration="300" />
<item android:drawable="@drawable/f4" android:duration="300" />
</animation-list>
我们可以将frame.xml文件放置于drawable或anim目录,官方文档上是放到了drawable中了,大家可以根据喜好来放置,放在这两个目录都是可以运行的。
我们定义了一个ImageView作为动画的载体,然后定义了两个按钮,分别是停止和启动动画。
接下来介绍一下如何通过加载动画定义文件来实现动画的效果。我们首先会这样写:
image = (ImageView) findViewById(R.id.frame_image);
image.setBackgroundResource(R.anim.frame);
AnimationDrawable anim = (AnimationDrawable) image.getBackground();
anim.start();
看似十分完美,跟官方文档上写的一样,然而当我们运行这个程序时会发现,它只停留在第一帧,并没有出现我们期望的动画,也许你会失望的说一句:“Why?”,然后你把相应的代码放在一个按钮的点击事件中,动画就顺利执行了,再移回到onCreate中,还是没效果,这个时候估计你会气急败坏的吼一句:“What the fuck!”。但是,什么原因呢?如何解决呢?
出现这种现象是因为当我们在onCreate中调用AnimationDrawable的start方法时,窗口Window对象还没有完全初始化,AnimationDrawable不能完全追加到窗口Window对象中,那么该怎么办呢?我们需要把这段代码放在onWindowFocusChanged方法中,当Activity展示给用户时,onWindowFocusChanged方法就会被调用,我们正是在这个时候实现我们的动画效果。当然,onWindowFocusChanged是在onCreate之后被调用的,如图:
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
image.setBackgroundResource(R.anim.frame);
AnimationDrawable anim = (AnimationDrawable) image.getBackground();
anim.start();
}
如果在有些场合,我们需要用纯代码方式实现一个动画,我们可以这样写:
AnimationDrawable anim = new AnimationDrawable();
for (int i = 1; i <= 4; i++) {
int id = getResources().getIdentifier("f" + i, "drawable", getPackageName());
Drawable drawable = getResources().getDrawable(id);
anim.addFrame(drawable, 300);
}
anim.setOneShot(false);
image.setBackgroundDrawable(anim);
anim.start();
学习不易,且学且珍惜。。。。。。。。
Interpolator对象 | 资源ID | 功能作用 |
---|---|---|
AccelerateDecelerateInterpolator | @android:anim/accelerate_decelerate_interpolator | 先加速再减速 |
AccelerateInterpolator | @android:anim/accelerate_interpolator | 加速 |
AnticipateInterpolator | @android:anim/anticipate_interpolator | 先回退一小步然后加速前进 |
AnticipateOvershootInterpolator | @android:anim/anticipate_overshoot_interpolator | 在上一个基础上超出终点一小步再回到终点 |
BounceInterpolator | @android:anim/bounce_interpolator | 最后阶段弹球效果 |
CycleInterpolator | @android:anim/cycle_interpolator | 周期运动 |
DecelerateInterpolator | @android:anim/decelerate_interpolator | 减速 |
LinearInterpolator | @android:anim/linear_interpolator | 匀速 |
OvershootInterpolator | @android:anim/overshoot_interpolator | 快速到达终点并超出一小步最后回到终点 |