一、概述
Android3.0以前的原生动画
视图动画,也叫Tween(补间)动画可以在一个视图容器内执行一系列简单变换(位置、大小、旋转、透明度)。譬如,如果你有一个TextView对象,您可以移动、旋转、缩放、透明度设置其文本,当然,如果它有一个背景图像,背景图像会随着
二、相关属性详解
2-1 Animation(Animation抽象类是所有补间动画类的基类,基类中提供的一些通用的动画属性方法)
xml属性 |
java方法 |
说明 |
android:detachWallpaper |
setDetachWallpaper(boolean) |
是否在壁纸上运行 |
android:duration |
setDuration(long) |
动画持续时间,毫秒为单位 |
android:fillAfter |
setFillAfter(boolean) |
控件动画结束时是否保持动画最后的状态 |
android:fillBefore |
setFillBefore(boolean) |
控件动画结束时是否还原到开始动画前的状态 |
android:fillEnabled |
setFillEnabled(boolean) |
与android:fillBefore效果相同 |
android:interpolator |
setInterpolator(Interpolator) |
设定插值器(指定的动画效果,譬如回弹等 |
android:repeatCount |
setRepeatCount(int) |
重复次数 |
android:repeatMode |
setRepeatMode(int) |
重复类型有两个值,reverse表示倒序回放,restart表示从头播放 |
android:startOffset |
setStartOffset(long) |
调用start函数之后等待开始运行的时间,单位为毫秒 |
android:zAdjustment |
setZAdjustment(int) |
表示被设置动画的内容运行时在Z轴上的位置(top/bottom/normal),默认为normal |
无论那种补间动画都具备以上的属性,可以是一个或多个,除此自外每种动画都有一些特有的属性;
2-2 AlpahAnimation(透明度动画)
xml属性 |
java方法 |
说明 |
android:fromAlpha |
AlphaAnimation(float fromAlpha, …) |
动画开始的透明度(0.0到1.0,0.0是全透明,1.0是不透明) |
android:toAlpha |
AlphaAnimation(…, float toAlpha) |
动画结束的透明度(0.0到1.0,0.0是全透明,1.0是不透明) |
2-3 RotateAnimation(旋转动画)
xml属性 |
java方法 |
说明 |
android:fromDegrees |
RotateAnimation(float fromDegrees, …) |
旋转开始角度,正代表顺时针度数,负代表逆时针度数 |
android:toDegrees |
RotateAnimation(…, float toDegrees, …) |
旋转结束角度,正代表顺时针度数,负代表逆时针度数 |
android:pivotX |
RotateAnimation(…, float pivotX, …) |
缩放起点X坐标(数值、百分数、百分数p,譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以当前View的左上角加上父控件宽高的50%做为初始点) |
android:pivotY |
RotateAnimation(…, float pivotY) |
缩放起点Y坐标,同上规律 |
2-3 ScaleAnimation(缩放动画)
xml属性 |
java方法 |
说明 |
android:fromXScale |
ScaleAnimation(float fromX, …) |
初始X轴缩放比例,1.0表示无变化 |
android:toXScale |
ScaleAnimation(…, float toX, …) |
结束X轴缩放比例 |
android:fromYScale |
ScaleAnimation(…, float fromY, …) |
初始Y轴缩放比例 |
android:toYScale |
ScaleAnimation(…, float toY, …) |
结束Y轴缩放比例 |
android:pivotX |
ScaleAnimation(…, float pivotX, …) |
缩放起点X轴坐标(数值、百分数、百分数p,譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以当前View的左上角加上父控件宽高的50%做为初始点) |
android:pivotY |
ScaleAnimation(…, float pivotY) |
缩放起点Y轴坐标,同上规律 |
2-4 TranslateAnimation(移动动画)
xml属性 |
java方法 |
说明 |
android:fromXDelta |
TranslateAnimation(float fromXDelta, …) |
起始点X轴坐标(数值、百分数、百分数p,譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以当前View的左上角加上父控件宽高的50%做为初始点) |
android:fromYDelta |
TranslateAnimation(…, float fromYDelta, …) |
起始点Y轴从标,同上规律 |
android:toXDelta |
TranslateAnimation(…, float toXDelta, …) |
结束点X轴坐标,同上规律 |
android:toYDelta |
TranslateAnimation(…, float toYDelta) |
结束点Y轴坐标,同上规律 |
2-5 AnimationSet
AnimationSet继承自Animation,是上面四种的组合容器管理类,没有自己特有的属性,他的属性继承自Animation,所以特别注意,当我们对set标签使用Animation的属性时会对该标签下的所有子控件都产生影响。
三、相关方法详解
3-1 Animation类
方法 |
说明 |
reset() |
重置Animation的初始化 |
cancel() |
取消Animation动画 |
start() |
开始Animation动画 |
setAnimationListener(AnimationListener listener) |
给当前Animation设置动画监听 |
hasStarted() |
判断当前Animation是否开始 |
hasEnded() |
判断当前Animation是否结束 |
3-2 View类的常用动画操作方法
方法 |
说明 |
startAnimation(Animation animation) |
对当前View开始设置的Animation动画 |
clearAnimation() |
取消当View在执行的Animation动画 |
3-3 注意事项
补间动画执行之后并未改变View的真实布局属性值。切记这一点,譬如我们在Activity中有一个View在屏幕上方,我们设置了平移动画移动到屏幕下方然后保持动画最后执行状态呆在屏幕下方,这时如果点击屏幕下方动画执行之后的View是没有任何反应的,而点击原来屏幕上方没有Button的地方却响应的是点击View的事件。
四、使用方法
4-1 Alpha
方法1:在XML中设置
- 1、在路径res/anim的文件夹里创建alpha.xml
- 2、根据动画效果设置不同的动画参数,从而实现透明动画效果。代码如下
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:fillAfter="true"
android:fromAlpha="1"
android:repeatCount="5"
android:repeatMode="reverse"
android:startOffset="500"
android:toAlpha="0"
android:interpolator="@android:anim/overshoot_interpolator"
></alpha>
Animation alphaAnimation = AnimationUtils.loadAnimation(this, R.anim.alpha);
tween_img.startAnimation(alphaAnimation);
//取消动画
tween_img.clearAnimation();
方法2:在java代码中设置(效果同上)
AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);
alphaAnimation.setDuration(3000);
alphaAnimation.setStartOffset(500);
alphaAnimation.setFillAfter(false);
alphaAnimation.setRepeatCount(5);
alphaAnimation.setRepeatMode(Animation.RESTART);
alphaAnimation.setInterpolator(new LinearInterpolator());
tween_img.startAnimation(alphaAnimation);
//取消动画
tween_img.clearAnimation();
4-2 Rotate
方法1:在XML中设置
- 1、在路径res/anim的文件夹里创建rotate.xml
- 2、根据动画效果设置不同的动画参数,从而实现透明动画效果。代码如下
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:fillAfter="true"
android:fillBefore="true"
android:fromDegrees="0"
android:interpolator="@android:anim/anticipate_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="5"
android:repeatMode="reverse"
android:startOffset="500"
android:toDegrees="180"
></rotate>
RotateAnimation rotateAnimation = AnimationUtils.loadAnimation(this, R.anim.rotate);
tween_img.startAnimation(rotateAnimation);
//取消动画
tween_img.clearAnimation();
方法2:在java代码中设置(效果同上)
// 伸缩模式,可以取值为ABSOLUTE、RELATIVE_TO_SELF、RELATIVE_TO_PARENT
// Animation.ABSOLUTE为绝对值 其他为百分比。
RotateAnimation rotateAnimation = new RotateAnimation(0, 270, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(3000);
rotateAnimation.setStartOffset(500);
rotateAnimation.setFillAfter(false);
rotateAnimation.setRepeatCount(5);
rotateAnimation.setRepeatMode(Animation.REVERSE);
rotateAnimation.setInterpolator(new LinearInterpolator());
tween_img.startAnimation(rotateAnimation);
//取消动画
tween_img.clearAnimation();
4-3 Scale
方法1:在XML中设置
- 1、在路径res/anim的文件夹里创建scale.xml
- 2、根据动画效果设置不同的动画参数,从而实现透明动画效果。代码如下
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:fillAfter="true"
android:fillBefore="true"
android:interpolator="@android:anim/overshoot_interpolator"
android:repeatCount="5"
android:repeatMode="reverse"
android:startOffset="500"
android:fromXScale="1"
android:fromYScale="1"
android:toXScale="0"
android:toYScale="0"
android:pivotY="50%"
android:pivotX="50%"
></scale>
ScaleAnimation scaleAnimation = AnimationUtils.loadAnimation(this, R.anim.scale);
tween_img.startAnimation(scaleAnimation);
//取消动画
tween_img.clearAnimation();
方法2:在java代码中设置(效果同上)
// 伸缩模式,可以取值为ABSOLUTE、RELATIVE_TO_SELF、RELATIVE_TO_PARENT
// Animation.ABSOLUTE为绝对值 其他为百分比。
AcaleAnimation scaleAnimation = new ScaleAnimation(1, 0, 1, 0, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(3000);
scaleAnimation.setStartOffset(500);
scaleAnimation.setFillAfter(false);
scaleAnimation.setRepeatCount(5);
scaleAnimation.setRepeatMode(Animation.REVERSE);
scaleAnimation.setInterpolator(new LinearInterpolator());
tween_img.startAnimation(scaleAnimation);
//取消动画
tween_img.clearAnimation();
4-4 Translate
方法1:在XML中设置
- 1、在路径res/anim的文件夹里创建translate.xml
- 2、根据动画效果设置不同的动画参数,从而实现透明动画效果。代码如下
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:fillAfter="true"
android:fillBefore="true"
android:interpolator="@android:anim/overshoot_interpolator"
android:repeatCount="5"
android:repeatMode="reverse"
android:startOffset="500"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="50%p"
android:toYDelta="0"
></translate>
TranslateAnimation translateAnimation = AnimationUtils.loadAnimation(this, R.anim.translate);
tween_img.startAnimation(translateAnimation);
//取消动画
tween_img.clearAnimation();
方法2:在java代码中设置(效果同上)
// 伸缩模式,可以取值为ABSOLUTE、RELATIVE_TO_SELF、RELATIVE_TO_PARENT
// Animation.ABSOLUTE为绝对值 其他为百分比。
TranslateAnimation translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, -0.5f, Animation.RELATIVE_TO_PARENT, 0.5f,
Animation.RELATIVE_TO_SELF, 0f,
Animation.ABSOLUTE, 0);
translateAnimation.setDuration(3000);
translateAnimation.setStartOffset(500);
translateAnimation.setFillAfter(true);
translateAnimation.setFillAfter(false);
translateAnimation.setRepeatCount(5);
translateAnimation.setRepeatMode(Animation.REVERSE);
translateAnimation.setInterpolator(new LinearInterpolator());
tween_img.startAnimation(translateAnimation);
//取消动画
tween_img.clearAnimation();
4-5 Set
方法1:在XML中设置
- 1、在路径res/anim的文件夹里创建set.xml
- 2、根据动画效果设置不同的动画参数,从而实现透明动画效果。代码如下
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fillAfter="true">
<rotate
android:duration="5000"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360" />
<translate
android:duration="5000"
android:fromXDelta="-50%p"
android:fromYDelta="0"
android:toXDelta="50%p"
android:toYDelta="0" />
<alpha
android:duration="5000"
android:fromAlpha="1.0"
android:toAlpha="0.0" />
<scale
android:duration="5000"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="0.5"
android:toYScale="0.5" />
</set>
AnimationSet setAnimation = AnimationUtils.loadAnimation(this, R.anim.set);
tween_img.startAnimation(setAnimation);
//取消动画
tween_img.clearAnimation();
方法2:在java代码中设置(效果同上)
//true使用集合的插值器,,false使用动画自己的插值器
AnimationSet animationSet = new AnimationSet(true);
animationSet.addAnimation(translateAnimation);
animationSet.addAnimation(alphaAnimation);
// animationSet.addAnimation(rotateAnimation);
// animationSet.addAnimation(scaleAnimation);
animationSet.setDuration(1000);
animationSet.setFillAfter(false);
tween_img.startAnimation(animationSet);
//取消动画
tween_img.clearAnimation();
五、动画监听
- Animation类通过监听动画开始 / 结束 / 重复时刻来进行一系列操作,如跳转页面等等
- 通过在 Java 代码里setAnimationListener()方法设置
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
//动画开始回调
}
@Override
public void onAnimationEnd(Animation animation) {
//动画结束回调
}
@Override
public void onAnimationRepeat(Animation animation) {
//重复执行动画回调
}
});
六、插值器(Interpolator)
6-1 插值器
- 1、作用:设置 属性值 从初始值过渡到结束值 的变化规律(如匀速、加速 & 减速 等等或者是明确了动画的变化模式)
- 2、应用场景:实现非线性运动的动画效果
- 3、系统提供的插值器(从源码中看,所有的插值器都实现Interpolator接口)
java类 |
xml 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 |
向前弹出一定值之后回到原来位置 |
插值器主要用于android动画中,用于改变动画变化的速率。Android自定义了很多种插值器,可以满足一般动画的需求。不过,当用户对自己的动画有很精细的要求,那就需要我们自己来定义动画的Interpolator了
6-2 自定义插值器
一、 基于三次方贝塞尔曲线的插值器
1、先使用贝塞尔曲线数值生成工具来获取想要的曲线数值
2、次方曲线插值器.(基于三次方贝塞尔曲线)
public class BezierInterpolator implements Interpolator {
private final static int ACCURACY = 4096;
private int mLastI = 0;
private final PointF mControlP1 = new PointF();
private final PointF mControlP2 = new PointF();
@Override
public float getInterpolation(float input) {
float t = input;
for (int i = mLastI; i < ACCURACY; i++) {
t = 1.0f * i / ACCURACY;
double x = cubicCurves(t, 0, mControlP1.x, mControlP2.x, 1);
if (x >= input) {
mLastI = i;
break;
}
}
double value = cubicCurves(t, 0, mControlP1.y, mControlP2.y, 1);
/* if (value > 0.999d) {
value = 1;
mLastI = 0;
}*/
return (float) value;
}
public BezierInterpolator(float x1, float y1, float x2, float y2) {
mControlP1.x = x1;
mControlP1.y = y1;
mControlP2.x = x2;
mControlP2.y = y2;
}
//求三次贝塞尔曲线(四个控制点)一个点某个维度的值
public double cubicCurves(double t, double value0, double value1, double value2, double value3) {
double value;
double u = 1 - t;
double tt = t * t;
double uu = u * u;
double uuu = uu * u;
double ttt = tt * t;
value = uuu * value0;
value += 3 * uu * t * value1;
value += 3 * u * tt * value2;
value += ttt * value3;
return value;
}
}
3、使用方法同上,只需把获取的曲线控制点传入即可
二、通过实现Interpolator类来实现
- 我们先来看看源码,看LinearInterpolator(匀速进行)是怎么实现的:
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
public LinearInterpolator() {
}
public LinearInterpolator(Context context, AttributeSet attrs) {
}
public float getInterpolation(float input) {
return input;
}
/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createLinearInterpolator();
}
}
- 再来看看稍微复杂一点的AccelerateDecelerateInterpolator(动画始末速率较慢,中间加速)是怎么实现的:
public class AccelerateDecelerateInterpolator extends BaseInterpolator
implements NativeInterpolatorFactory {
public AccelerateDecelerateInterpolator() {
}
@SuppressWarnings({"UnusedDeclaration"})
public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {
}
public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createAccelerateDecelerateInterpolator();
}
- 分析
// input的运算逻辑如下:
// 使用了余弦函数,因input的取值范围是0到1,那么cos函数中的取值范围就是π到2π。
// 而cos(π)的结果是-1,cos(2π)的结果是1
// 所以该值除以2加上0.5后,getInterpolation()方法最终返回的结果值还是在0到1之间。只不过经过了余弦运算之后,最终的结果不再是匀速增加的了,而是经历了一个先加速后减速的过程
// 所以最终,fraction值 = 运算后的值 = 先加速后减速
// 所以该差值器是先加速再减速的
- 定义SpringInterpolator(弹簧效果)
public class SpringInterpolator implements Interpolator {
private static final float factor = 0.2f;
private float mFactor;
public SpringInterpolator(float factor) {
this.mFactor = factor;
}
public SpringInterpolator() {
this(factor);
}
@Override
public float getInterpolation(float input) {
// factor = 0.1
// pow(2, -10 * x) * sin((x - factor / 4) * (2 * PI) / factor) + 1
float out = (float) (Math.pow(2, -10 * input) * Math.sin((input - mFactor / 4) * (2 * Math.PI) / mFactor) + 1);
if(mListener!=null){
mListener.onInterpolationChange(input,out);
}
return out;
}
public interface onInterpolationChangeListener
{
void onInterpolationChange(float y, float t);
}
onInterpolationChangeListener mListener = null;
public void setOnInterpolationListener(onInterpolationChangeListener listener){
mListener = listener;
}
}
到这里一个自定义的Interpolator就完成了,主要的难点就在公式计算了,分享一个可视化插值器的网站,其中内置了一些插值器公式,还可以查看动画演示效果
七、应用场景
7-1 标准的动画效果
- 补间动画常用于视图View的一些标准动画效果:平移、旋转、缩放 & 透明度
7-2 特殊的应用场景
Activity启动动画(自定义左右滑动效果)
需要定义四个动画,两个activity的进入和退出动画
<translate
android:duration="500"
android:fromXDelta="100%p"
android:toXDelta="0%p" />
<translate
android:duration="500"
android:fromXDelta="0%p"
android:toXDelta="-100%p" />
<translate
android:duration="500"
android:fromXDelta="-100%p"
android:toXDelta="0%p" />
<translate
android:duration="500"
android:fromXDelta="0%p"
android:toXDelta="100%p"/>
使用方法
startActivity(new Intent(TweenActivity.this, InterpolatorActivity.class));
overridePendingTransition(R.anim.activity_start_in_animation,R.anim.activity_start_out_animation);
@Override
public void finish() {
super.finish();
overridePendingTransition(R.anim.activity_finish_in_animation, R.anim.activity_finish_out_animation);
}
网友评论