Android动画学习笔记

本文详细介绍了Android中的补间动画,包括平移、缩放、旋转和透明度动画的XML与Java设置方法,以及如何使用组合动画。同时深入探讨了属性动画,特别是ValueAnimator和ObjectAnimator的使用,以及自定义插值器和估值器的实现。

Android 动画

补间动画

根据不同的动画效果,补间动画分为4种

  • 平移动画
  • 缩放动画
  • 旋转动画
  • 透明度动画

动画属性既可以在xml中设置,也可以在java代码中写

插值器Interpolator

简单的来说插值器就是返回当前动画的进度,然后根据进度设置动画当前的效果

这是给动画设置插值器的方法

android:interpolator="@android:anim/accelerate_interpolator"
    
animator.setInterpolator(new BounceInterpolator());
作用资源ID对应Java类
动画加速进行@android:anim/accelerate_interpolatorAccelerateInterpolator
快速完成动画,超出再回到结束样式@android:anim/overshoot_interpolatorOvershootInterpolator
先加速再减速@android:anim/accelerate_decelerate_interpolatorAccelerateDecelerateInterpolator
先退后再加速前进@android:anim/anticipate_interpolatorAnticipateInterpolator
先退后再加速前进,超出终点后再回终点@android:anim/anticipate_overshoot_interpolatorAnticipateOvershootInterpolator
最后阶段弹球效果@android:anim/bounce_interpolatorBounceInterpolator
周期运动@android:anim/cycle_interpolatorCycleInterpolator
减速@android:anim/decelerate_interpolatorDecelerateInterpolator
匀速@android:anim/linear_interpolatorLinearInterpolator
AccelerateInterpolator插值器
public float getInterpolation(float input) {
    if (mFactor == 1.0f) {
        return input * input;
    } else {
        return (float)Math.pow(input, mDoubleFactor);
    }
}
自定义插值器

自定义插值器只需要实现TimeInterpolator接口就行

public class MyInterploator implements Interpolator {
    @Override
    public float getInterpolation(float input) {
        return 1-input;
    }
}

这个插值器的就能将动画由设置的终点向起点进行

一、平移动画(Translate)

1.在xml中设置相关属性

<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"//动画持续时间,必须设置
    android:startOffset="1000"//动画延迟开始时间
    android:fillBefore="true"//动画播放完毕后是否停留在动画开始状态默认为true
    android:fillAfter="false"//动画播放完毕后是否停留在结束状态默认为false且优先级高于fillBefore
    android:fillEnabled="true"//是否应用fillBefore值对fillAfter无影响
    android:repeatMode="restart"//重复动画模式 restart(正序) reverse(倒序) 默认为正序
    android:repeatCount="0"//重复播放次数
    //以上是补间动画都有的属性
    //以下是平移动画默认的属性
    android:fromXDelta="50%p"//视图在水平方向x的起始值
    android:toXDelta="50%"//视图在水平方向x的结束值
    android:fromYDelta="20"//竖直方向的起始值
    android:toYDelta="50%"//竖直方向的终止值
    >
</translate>

2.在活动中为控件关联动画

translate = findViewById(R.id.button1);
Animation translateAnimation = AnimationUtils.loadAnimation(this,R.anim.translate);
translate.startAnimation(translateAnimation);

3.在JAVA代码中设置动画

translate = findViewById(R.id.button1);
Animation translateAnimation = new TranslateAnimation(0,500,0,500);
//4个参数分别是x起始值、x终止值、y起始值、y终止值
translateAnimation.setDuration(3000);
translate.startAnimation(translateAnimation);

上面的值有三种

  • xxx% 相对于自身控件的大小
  • xxx%p 相对于父容器的大小
  • xxx 固定大小

需要注意的是上面的起始值和终止值都是起始位置与控件原本位置的距离

二、缩放动画(Scale)

1.在xml中设置相关属性

<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXScale="0"//动画在水平方向的起始缩放倍数
    //0零表示收缩到无
    //1表示无缩放
    android:toXScale="2"//水平结束倍数
    android:fromYScale="1"
    android:toYScale="2"
    android:pivotX="50%"//缩放轴点
    android:pivotY="50%"//缩放轴点        android:duration="3000"
    >
</scale>

2.在活动中为控件关联动画

scale = findViewById(R.id.button2);
Animation scaleAnimation = AnimationUtils.loadAnimation(this,R.anim.scale);
scale.startAnimation(scaleAnimation);

3.在Java中设置动画

 scale = findViewById(R.id.button2);
Animation scaleAnimation = new ScaleAnimation(0,2,0,2,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
scaleAnimation.setDuration(3000);
//前4个参数分别为xy的起始终止zhi
// 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方向同理)
scale.startAnimation(scaleAnimation);

三、旋转动画

1.在xml中设置相关属性

<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromDegrees="0"//动画开始旋转角度
    android:toDegrees="360"//结束旋转角度
    android:pivotX="50%"//旋转节点
    android:pivotY="50%"
    android:duration="3000"
    >
</rotate>

2.在活动中为控件关联动画

rotate = findViewById(R.id.button3);
Animation rotateAnimation = AnimationUtils.loadAnimation(this,R.anim.rotate);
rotate.startAnimation(rotateAnimation);

3.在Java中设置动画

rotate = findViewById(R.id.button3);
Animation rotateAnimation =  new RotateAnimation(0,270,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
scaleAnimation.setDuration(3000);
// 1. fromDegrees :动画开始时 视图的旋转角度(正数 = 顺时针,负数 = 逆时针) 
// 2. toDegrees :动画结束时 视图的旋转角度(正数 = 顺时针,负数 = 逆时针) 
// 3. pivotXType:旋转轴点的x坐标的模式 
// 4. pivotXValue:旋转轴点x坐标的相对值 
// 5. pivotYType:旋转轴点的y坐标的模式 
// 6. pivotYValue:旋转轴点y坐标的相对值
//模式值同样分为 Animation.RELATIVE_ABSLUTE、Animation.RELATIVE_TO_SELF、Animation.RELATIVE_TO_PARENT
rotate.startAnimation(rotateAnimation);

四、透明度动画

1.在xml中设置相关属性

<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromAlpha="1.0"//动画开始透明度(范围: -1~1)
    android:toAlpha="0.0"//结束透明度
    android:duration="2000"
    android:fillAfter="true">
</alpha>

2.在活动中为控件关联动画

alpha = findViewById(R.id.button4);
Animation alphaAnimation = AnimationUtils.loadAnimation(this,R.anim.rotate);
alpha.startAnimation(alphaAnimation);

3.在Java中设置动画

alpha = findViewById(R.id.button4);
Animation alphaAnimation = new AlphaAnimation(1,0);
alphaAnimation.setDuration(3000);
alpha.startAnimation(alphaAnimation);

五、组合动画

1.在xml中设置相关属性

<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="5000"
    android:shareInterpolator="true"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:repeatMode="reverse"
    >
    <alpha
        android:fromAlpha="1.0"
        android:toAlpha="0.0"
        android:duration="2000"
        android:fillAfter="true"
        />
    <translate
        android:fromXDelta="100%"
        android:fromYDelta="100%"
        android:toXDelta="0%"
        android:toYDelta="0%"
        android:duration="2000"
        />
    <rotate
        android:fromDegrees="0"
        android:toDegrees="360"
        android:pivotX="50%"
        android:pivotY="50%"
        android:duration="3000"
        />
    <scale
        android:fromXScale="1"
        android:toXScale="2"
        android:fromYScale="1"
        android:toYScale="2"
        android:pivotX="50%"
        android:pivotY="50%"
        android:duration="3000"
        />
</set>

2.在活动中为控件关联动画

set = findViewById(R.id.button5);
Animation setAnimation = AnimationUtils.loadAnimation(this,R.anim.set);
set.startAnimation(setAnimation);

3.在Java中设置动画

set = findViewById(R.id.button5);
Animation scaleAnimation = new ScaleAnimation(0,2,0,2,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
scaleAnimation.setDuration(3000);

Animation rotateAnimation =  new RotateAnimation(0,270,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
rotateAnimation.setDuration(3000);

Animation alphaAnimation = new AlphaAnimation(1,0);
alphaAnimation.setDuration(3000);

Animation   translateAnimation = new TranslateAnimation(0,500,0,500);
translateAnimation.setDuration(3000);
        
AnimationSet setAnimation = new AnimationSet(true);
setAnimation.addAnimation(translateAnimation);
setAnimation.addAnimation(scaleAnimation);
setAnimation.addAnimation(rotateAnimation);
setAnimation.addAnimation(alphaAnimation);
set.startAnimation(setAnimation);

动画的一部分效果图
avr

监听回调

animation.setAnimationListener(new Animation.AnimayionListener(){
    @Override
    public void onAnimationStart(Animation animation){
        
    }
    @Override
    public void onAnimationEnd(Animation animation){
        
    }
    @Override
    public void onAnimationRepeat(Animation animation){
        
    }
}

属性动画

ValueAnimatior

这个是属性动画中核心的东西

它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等,确实是一个非常重要的类。

下面的代码就将0较为平滑的过度到100

    ValueAnimator anim = ValueAnimator.ofInt(1,  100);
    anim.setDuration(500);
    anim.setStartDelay(500);
    anim.setRepeatCount(0);
    anim.setRepeatMode(ValueAnimator.RESTART);

    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            int currentValue = (Integer)animation.getAnimatedValue();
            Log.d("TAG", "cuurent value is " + currentValue);
        }
    });
    anim.start();

image

ObjectAnimatior

这里如果我们想要将一个TextView在5秒中内从常规变换成全透明,再从全透明变换成常规,就可以这样写:

ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
animator.setDuration(5000);
animator.start();

插值器TimeInterpolator 估值器TypeEvaluator

插值器就是返回当前动画的进度,然后将进度以百分比的形式传递给估值器

估值器相当于一个转换器,得到插值器给的百分比以后,将这个百分比转换为具体的值去赋值给对象,再进行重绘

插值器决定值的变化规律,而值的具体变化交给估值器

其实ValueAnimator的过度就是以这2个为基础的。

自定义估值器

先看一下IntEvaluator的源码

public class IntEvaluator implements TypeEvaluator<Integer> {
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return (int)(startInt + fraction * (endValue - startInt));
    }
}

自定义估值器需要实现TypeEvaluator接口&复写evaluate.

public class MyEvaluator implements TypeEvaluator{

    @Override
    public Object evaluate(float fraction, Object startValue, Object endValue){
        Point start = (Point) startValue;
        Point end = (Point) endValue;
        float x = end.getX() - start.getX();
        float y = end.getY() - start.getY();
        x = start.getX()+x*fraction;
        y = (float) (y*Math.sin((double) fraction*Math.PI));
        Point point = new Point(x,y);
        return point;
    }
}

public class MyAnimationView extends View {
    public static final float RADIUS = 50f;

    private Point currentPoint;

    private Paint mPaint;

    public MyAnimationView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.BLUE);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        if (currentPoint == null) {
            currentPoint = new Point(RADIUS, RADIUS);
            drawCircle(canvas);
        } else {
            drawCircle(canvas);
        }
    }
    public void setCurrentPoint(Point point){
        currentPoint = point;
        invalidate();
    }

    private void drawCircle(Canvas canvas) {
        float x = currentPoint.getX();
        float y = currentPoint.getY();
        canvas.drawCircle(x, y, RADIUS, mPaint);
    }
}



    @Override
public void onClick(View view){
    switch (view.getId()){
        case R.id.start:
            Point start = new Point(50,50);
            Point end = new Point(1500,1500);
            ValueAnimator animator = ValueAnimator.ofObject(new MyEvaluator(),start,end);
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    Point point = (Point) animation.getAnimatedValue();
                    myAnimationView.setCurrentPoint(point);
                    Log.d("dddd","pointx:"+point.getX()+" pointy:"+point.getY());
                }
            });
            animator.setDuration(5000);
            animator.start();
            break;
    }
}

images

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值