补间动画
只能作用在view上,只有四种动画,只是改变view的视觉效果,不会改变view真正的属性
效果有:平移(Translate),缩放(scale),旋转(rotate),透明度(alpha)
补间动画使用方式,在anim创建xml文件,使用代码动态开启动画
平移动画 translate
使用xml
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
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 移动的结束值 />
java代码
Animation animation = AnimationUtils.loadAnimation(this, R.anim.translateanim);
button.startAnimation(animation);
TranslateAnimation translateAnimation = new TranslateAnimation(0, 500, 0, 500);
translateAnimation.setDuration(2000);
button.startAnimation(translateAnimation);
缩放动画 scale
使用xml
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
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 />
java 代码
Button mButton = (Button) findViewById(R.id.Button);
// 步骤1:创建 需要设置动画的 视图View
Animation rotateAnimation = AnimationUtils.loadAnimation(this, R.anim.view_animation);
// 步骤2:创建 动画对象 并传入设置的动画效果xml文件
mButton.startAnimation(scaleAnimation);
Button mButton = (Button) findViewById(R.id.Button);
Animation rotateAnimation = new ScaleAnimation(0,2,0,2,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
// 步骤2:创建缩放动画的对象 & 设置动画效果:缩放动画对应的Animation子类为RotateAnimation
// 参数说明:
// 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方向同理)
scaleAnimation.setDuration(3000);
mButton.startAnimation(scaleAnimation);
旋转动画 rotate
使用xml
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromDegrees="0" // 动画开始时 视图的旋转角度(正数 = 顺时针,负数 = 逆时针)
android:toDegrees="270" // 动画结束时 视图的旋转角度(正数 = 顺时针,负数 = 逆时针)
android:pivotX="50%" // 旋转轴点的x坐标
android:pivotY="0" // 旋转轴点的y坐标 />
java 代码
Animation rotateAnimation = new RotateAnimation(0, 270, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(2000);
button.startAnimation(rotateAnimation);
透明度
使用 xml
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
// 以下参数是透明度动画特有的属性
android:fromAlpha="1.0" // 动画开始时视图的透明度(取值范围: -1 ~ 1)
android:toAlpha="0.0"// 动画结束时视图的透明度(取值范围: -1 ~ 1)/>
java 代码
Button mButton = (Button) findViewById(R.id.Button);
// 步骤1:创建 需要设置动画的 视图View
Animation alphaAnimation = new AlphaAnimation(1,0);
// 步骤2:创建透明度动画的对象 & 设置动画效果:透明度动画对应的Animation子类为AlphaAnimation
// 参数说明:
// 1. fromAlpha:动画开始时视图的透明度(取值范围: -1 ~ 1)
// 2. toAlpha:动画结束时视图的透明度(取值范围: -1 ~ 1)
alphaAnimation.setDuration(3000);
// 固定属性的设置都是在其属性前加“set”,如setDuration()
mButton.startAnimation(alphaAnimation);
组合动画
使用 xml
<?xml version="1.0" encoding="utf-8"?>
// 采用< Set/>标签
<set xmlns:android="http://schemas.android.com/apk/res/android">
// 组合动画独特的属性
android:shareinterpolator = “true”
// 表示组合动画中的动画是否和集合共享同一个差值器
// 如果集合不指定插值器,那么子动画需要单独设置
// 组合动画播放时是全部动画同时开始
// 如果想不同动画不同时间开始就要使用android:startOffset属性来延迟单个动画播放时间
<rotate
android:duration="1000"
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"
android:repeatMode="restart"
android:repeatCount="infinite"/>
<translate
android:duration="10000"
android:startOffset = “1000”
android:fromXDelta="-50%p"
android:fromYDelta="0"
android:toXDelta="50%p"
android:toYDelta="0" />
<alpha
android:startOffset="7000"
android:duration="3000"
android:fromAlpha="1.0"
android:toAlpha="0.0" />
<scale
android:startOffset="4000"
android:duration="1000"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="0.5"
android:toYScale="0.5"/>
1. 在组合动画里scale缩放动画设置的repeatCount(重复播放)和fillBefore(播放完后,视图是否会停留在动画开始的状态)是无效的。
2. 所以如果需要重复播放或者回到原位的话需要在set标签里设置
3. 但是由于此处rotate旋转动画里已设置repeatCount为infinite,所以动画不会结束,也就看不到重播和回复原位
</set>
使用 java代码
Button mButton = (Button) findViewById(R.id.Button);
// 创建 需要设置动画的 视图View
// 组合动画设置
AnimationSet setAnimation = new AnimationSet(true);
// 步骤1:创建组合动画对象(设置为true)
// 步骤2:设置组合动画的属性
// 特别说明以下情况
// 因为在下面的旋转动画设置了无限循环(RepeatCount = INFINITE)
// 所以动画不会结束,而是无限循环
// 所以组合动画的下面两行设置是无效的
setAnimation.setRepeatMode(Animation.RESTART);
setAnimation.setRepeatCount(1);// 设置了循环一次,但无效
// 子动画1:旋转动画
Animation rotate = new RotateAnimation(0,360,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
rotate.setDuration(1000);
rotate.setRepeatMode(Animation.RESTART);
rotate.setRepeatCount(Animation.INFINITE);
// 子动画2:平移动画
Animation translate = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_PARENT,-0.5f,
TranslateAnimation.RELATIVE_TO_PARENT,0.5f,
TranslateAnimation.RELATIVE_TO_SELF,0
,TranslateAnimation.RELATIVE_TO_SELF,0);
translate.setDuration(10000);
// 子动画3:透明度动画
Animation alpha = new AlphaAnimation(1,0);
alpha.setDuration(3000);
alpha.setStartOffset(7000);
// 子动画4:缩放动画
Animation scale1 = new ScaleAnimation(1,0.5f,1,0.5f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
scale1.setDuration(1000);
scale1.setStartOffset(4000);
// 步骤4:将创建的子动画添加到组合动画里
setAnimation.addAnimation(alpha);
setAnimation.addAnimation(rotate);
setAnimation.addAnimation(translate);
setAnimation.addAnimation(scale1);
mButton.startAnimation(setAnimation);
帧动画,将动画切割为多张图片
使用xml创建
<?xml version="1.0" encoding="utf-8"?>
<animation-list
xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true"
// 设置是否只播放一次,默认为false>
//item = 动画图片资源;duration = 设置一帧持续时间(ms)
<item android:drawable="@drawable/a0" android:duration="100"/>
<item android:drawable="@drawable/a1" android:duration="100"/>
<item android:drawable="@drawable/a2" android:duration="100"/>
<item android:drawable="@drawable/a3" android:duration="100"/>
<item android:drawable="@drawable/a4" android:duration="100"/>
<item android:drawable="@drawable/a5" android:duration="100"/>
<item android:drawable="@drawable/a6" android:duration="100"/>
<item android:drawable="@drawable/a7" android:duration="100"/>
</animation-list>
使用java代码
ImageView imageView = new ImageView(this);
imageView.setImageResource(R.drawable.ic_launcher_background);
AnimationDrawable animationDrawable = (AnimationDrawable) imageView.getDrawable();
animationDrawable.start();
animationDrawable.stop();
//动态创建帧动画
AnimationDrawable animationDrawable1 = new AnimationDrawable();
for (int i = 0; i < 10; i++) {
int drawable = getResources().getIdentifier("aaa" + i, "drawable", getPackageName());
Drawable drawable1 = getResources().getDrawable(drawable);
animationDrawable1.addFrame(drawable1,100);
}
animationDrawable1.setOneShot(true);
ImageView imageView1 = new ImageView(this);
imageView.setImageResource(R.drawable.ic_launcher_background);
//开启动画之前先停止动画,不然第一次动画之后会停留在最后一帧,这样动画就只会触发一次
animationDrawable1.stop();
animationDrawable1.start();
监听动画过程
alphaAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
属性动画可以采用以下监听
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0.0f, 120f);
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
}
});
属性动画
3.0之后出现。顾名思义,为了改变view的某一个属性的动画
使用步骤如下:
- 设置动画运行时长,动画效果以及对应属性的初始值和结束值
- 设置从开始到结束的变化逻辑
- 设置值变化的模式趋势使用插值器,自定义插值器需要实现interpolator接口
- 设置值变化的具体数值使用估值器,自定义估值器实现TypeEvaluator接口
- 根据变化不断改变值得效果
- 值每改变一次,就赋值给view的属性一次,
- 手动赋值使用-valueAnimator
- 自动赋值使用-ObjectAnimator
- 每次调用invalidate();不断刷新视图直到初始值变为结束值
ValueAnimator 手动赋值给对象的属性,实现动画效果
自带估值器有:
- ValueAnimator ofInt(int... values),整型估值器
- ValueAnimator ofFloat(float... values) ,浮点型估值器
- ValueAnimator ofObject(TypeEvaluator evaluator, Object... values)操作对象实现动画效果
整型或者浮点型估值器
//设置动画属性的初始值以及结束值,ofInt创建动画实例,讲传入的多个Int型参数进行平滑过渡,内置整型估值器,直接使用默认
final ValueAnimator valueAnimator = ValueAnimator.ofInt(100, 180, 500, 700, 600);
mButton = findViewById(R.id.button2);
valueAnimator.setDuration(2000);//播放时间
valueAnimator.setStartDelay(100);//延迟播放时间
valueAnimator.setRepeatCount(0);//设置播放次数,-1就是无限循环
valueAnimator.setRepeatMode(ValueAnimator.REVERSE);//设置重复播放模式ValueAnimator.RESTART(默认):正序重放,ValueAnimator.REVERSE:倒序回放
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int animatedValue = (Integer) valueAnimator.getAnimatedValue();
mButton.setText("---" + animatedValue);
mButton.setTranslationX(animatedValue);
mButton.getLayoutParams().width = animatedValue;
mButton.getLayoutParams().height = animatedValue;
mButton.setRotation(animatedValue);
mButton.setAlpha(animatedValue);
mButton.requestLayout();//刷新view的位置
}
});
valueAnimator.start();
ValueAnimator.ofObject()将初始值 以对象的形式 过渡到结束值
public class ObjectEvaluatorView extends View {
private Paint mPaint;
private Point mPoint;
private static final int ROUND = 81;
public ObjectEvaluatorView(Context context) {
this(context, null);
}
public ObjectEvaluatorView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public ObjectEvaluatorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.YELLOW);
mPaint.setTextSize(120);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mPoint == null) {
mPoint = new Point(ROUND,ROUND);
canvas.drawCircle(ROUND,ROUND,ROUND,mPaint);
Point point = new Point(600, 800);
Point point3 = new Point(80, 1200);
Point point4 = new Point(80, 80);
ValueAnimator valueAnimator = ValueAnimator.ofObject(new ObjectEvaluator(), mPoint, point,point3,point4);
valueAnimator.setDuration(3000);
valueAnimator.setRepeatCount(-1);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mPoint = (Point) animation.getAnimatedValue();
invalidate();
}
});
valueAnimator.start();
}else {
canvas.drawText("😄",mPoint.getX(),mPoint.getY(),mPaint);
}
}
}
ObjectAnimator自动赋值实现动画效果,直接操作对象的属性
基本的四种属性:
ObjectAnimator alpha = ObjectAnimator.ofFloat(mButton3, "alpha", 1f, 0f, 100f);
alpha.setDuration(3000);
alpha.setRepeatCount(-1);
alpha.start();
ObjectAnimator rotation = ObjectAnimator.ofFloat(mButton3, "rotation", 1f, 360f, 100f);
rotation.setDuration(3000);
rotation.setRepeatCount(-1);
rotation.start();
ObjectAnimator translationX = ObjectAnimator.ofFloat(mButton3, "translationY", 1f, 360f, 100f);
translationX.setDuration(3000);
translationX.setRepeatCount(-1);
translationX.start();
ObjectAnimator scaleY = ObjectAnimator.ofFloat(mButton3, "scaleY", 1f, 4f, 1f);
scaleY.setDuration(3000);
scaleY.setRepeatCount(-1);
scaleY.start();
属性 | 作用 |
---|---|
Alpha | 控制view的透明度 |
TranslationX | 控制x轴方向位移 |
TranslationY | K通知y轴方向位移 |
ScaleX | 控制x轴方向缩放倍数 |
ScaleY | 控制y轴方向缩放倍数 |
Rotation | 控制以屏幕方向为轴的旋转度数 |
RotationX | 控制以x轴为轴的旋转度数 |
RotationY | 控制以y轴为轴的旋转度数 |
扩展自定义属性
两种方式:
- 通过集成原始类,添加get()和set()方法
public class MyView2 extends View {
// 设置需要用到的变量
public static final float RADIUS = 100f;// 圆的半径 = 100
private Paint mPaint;// 绘图画笔
private String color;
// 设置背景颜色属性
// 设置背景颜色的get() & set()方法
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
mPaint.setColor(Color.parseColor(color));
// 将画笔的颜色设置成方法参数传入的颜色
invalidate();
// 调用了invalidate()方法,即画笔颜色每次改变都会刷新视图,然后调用onDraw()方法重新绘制圆
// 而因为每次调用onDraw()方法时画笔的颜色都会改变,所以圆的颜色也会改变
}
// 构造方法(初始化画笔)
public MyView2(Context context, AttributeSet attrs) {
super(context, attrs);
// 初始化画笔
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.BLUE);
}
// 复写onDraw()从而实现绘制逻辑
// 绘制逻辑:先在初始点画圆,通过监听当前坐标值(currentPoint)的变化,每次变化都调用onDraw()重新绘制圆,从而实现圆的平移动画效果
@Override
protected void onDraw(Canvas canvas) {
canvas.drawCircle(500, 500, RADIUS, mPaint);
}
}
- 添加包装类,传递对象进入,封装get()和set()方法
ObjectAnimator alpha = ObjectAnimator.ofObject(new Test(mButton3), "text", new Bbb(), "asdasd", "qweqweqweqw", "zxczxczxczc");
alpha.setDuration(3000);
alpha.setRepeatCount(-1);
alpha.start();
//自定义包装类
private class Test{
private Button mView;
public Test(Button view) {
mView = view;
}
public String getText(){
return mView.getText().toString();
}
public void setText(String s){
mView.setText(s);
}
}
//自定义估值器
private class Bbb implements TypeEvaluator {
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
return startValue;
}
}
组合动画
AnimatorSet.play(Animator anim) :播放动画
AnimatorSet.after(long delay) :动画延迟x毫秒后执行
AnimatorSet.with(Animator anim) :现有动画和传入的动画同时执行
AnimatorSet.after(Animator anim) :现有动画插入到传入的动画之后执行
AnimatorSet.before(Animator anim) : 现有动画插入到传入的动画之前执行
使用方式如下:
// 步骤1:设置需要组合的动画效果
ObjectAnimator translation = ObjectAnimator.ofFloat(mButton, "translationX", curTranslationX, 300,curTranslationX);
ObjectAnimator rotate = ObjectAnimator.ofFloat(mButton, "rotation", 0f, 360f);
ObjectAnimator alpha = ObjectAnimator.ofFloat(mButton, "alpha", 1f, 0f, 1f);
AnimatorSet animSet = new AnimatorSet();
animSet.play(translation).with(rotate).before(alpha);
animSet.setDuration(5000);
animSet.start();
属性动画简写方式:
mButton = (Button) findViewById(R.id.Button);
mButton.animate().alpha(0f);
mButton.animate().alpha(0f).setDuration(5000).setInterpolator(new BounceInterpolator());
mButton.animate().alpha(0f).x(500).y(500);
插值器和估值器
- 设置值变化的模式趋势使用插值器,自定义插值器需要实现interpolator接口
- 设置值变化的具体数值使用估值器,自定义估值器实现TypeEvaluator接口
系统默认自带插值器有:
java类 | 作用 |
---|---|
AccelerateInterpolator | 加速,开始时慢中间加速,系统默认 |
DecelerateInterpolator | 减速,开始时快然后减速 |
AccelerateDecelerateInterolator | 先加速后减速,开始结束时慢,中间加速 |
AnticipateInterpolator | 反向,先向相反方向改变一段再加速播放 |
AnticipateOvershootInterpolator | 反向加超越,先向相反方向改变,再加速播放,会超出目的值然后缓慢移动至目的值 |
BounceInterpolator | 跳跃,快到目的值时值会跳跃,如目的值100,后面的值可能依次为85,77,70,80,90,100 |
CycleIinterpolator | 循环,动画循环一定次数,值的改变为一正弦函数:Math.sin(2* mCycles* Math.PI* input) |
LinearInterpolator | 线性,线性均匀改变 |
OvershootInterpolator | 超越,最后超出目的值然后缓慢改变到目的值 |
自定义插值器
补间动画 实现 Interpolator接口;属性动画实现TimeInterpolator接口
private class Ccc implements TimeInterpolator {
/**
* @param input 范围变化1-0,
* @return
*/
@Override
public float getInterpolation(float input) {
float aa;
if (input <= 0.5) {
aa = (float) ((Math.sin(Math.PI * input)) / 2);
} else {
aa = (float) (2 - Math.sin(Math.PI * input) / 2);
}
return aa;
}
}
自定义估值器
private class Bbb implements TypeEvaluator {
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
return startValue;
}
}