android Tween动画和属性动画

动画主要分为两种一种是Tween动画,一种 是属性动画。
Tween动画有分为帧动画和补间动画。
帧动画
作用对象: 只能是View,如ImageView Button等。
原理:把一张张图片连起来播放,视觉上看起来像动画一样。
特点: 使用简单,方便 但是使用图片过多导致包过大而且容易OOM。
具体使用:
首先在drawable目录新建一个frame_anim.xml 内容如下:

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="true">
    <item android:drawable="@drawable/icon_logo" android:duration="1000"/>
    <item android:drawable="@drawable/ic_launcher_background" android:duration="1000"/>
    <item android:drawable="@drawable/ic_launcher" android:duration="1000"/>
</animation-list>

java代码如下

imageView.setBackgroundResource(R.drawable.frame_anim);
AnimationDrawable animation = (AnimationDrawable)imageView.getBackground();
animation.start();

补间动画
作用对象:和帧动画一样,只能针对View。

原理:通过确定开始视图的样子和结束视图的样子,中间的动画变化由系统帮我们补全。

分类:动画分为四类,位移(TranslateAnimation)动画、 缩放(ScaleAnimation)动画、透明(AlphaAnimation)动画、旋转(RotateAnimation)动画。

具体使用:可以在XML中定义,也可以在java代码中定义。

使用场景:现在常见的使用场景就是Activity fragment或者ViewGroup子类替换用(XML转场动画复用率比较高)。

属性动画
作用对象:任意java对象。

实现动画效果:可以实现任意的动画效果,并不一定只是定义的那四种。

原理:在一定的时间间隔内不断的是值进行改变,并且不断的将值赋值给对象的属性,从而实现该对象在改属性上的动画效果,这里可以是任意对象的任意属性。可以通过Interpolator来改变值变化的速率,通过TypeEvaluator来的操作。

实现属性动画主要有两个类一个是ValueAnimator和ObjectAnimator。
ValueAnimator
它的用法主要有三种
ValueAnimator.ofInt
设置开始值和结束值,然后设置addUpdateListener来监听值的变化从而来实现动画效果。

ValueAnimator.ofFloat
和ValueAnimator.ofInt类似,只是估值器不一样,ValueAnimator.ofFloat采用的是FloatEvaluator估值器;ValueAnimator.ofInt用的是IntEvaluator估值器。

public class FloatEvaluator implements TypeEvaluator<Number> {
    public Float evaluate(float fraction, Number startValue, Number endValue) {
        float startFloat = startValue.floatValue();
        return startFloat + fraction * (endValue.floatValue() - startFloat);
    }
}

ValueAnimator.ofObject
相对与上面两个这个相对复杂一点,需要自己定义估值器。

public class Point {

    private float x;
    private float y;

    public Point(float x, float y) {
        this.x = x;
        this.y = y;
    }

    public float getX() {
        return x;
    }

    public void setX(float x) {
        this.x = x;
    }

    public float getY() {
        return y;
    }

    public void setY(float y) {
        this.y = y;
    }
}


public class MyView extends View {

    public static final float RADIUS = 30f;
    private Paint mPaint;
    private float x;
    private float y;

    @Override
    public float getX() {
        return x;
    }

    @Override
    public void setX(float x) {
        this.x = x;
    }

    @Override
    public float getY() {
        return y;
    }

    @Override
    public void setY(float y) {
        this.y = y;
    }

    public MyView(Context context) {
        this(context, null);
    }

    public MyView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, -1);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.YELLOW);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawCircle(x, y, RADIUS, mPaint);
    }
}

public class PointEvaluator implements TypeEvaluator {
    @Override
    public Object evaluate(float fraction, Object startValue, Object endValue) {
        Point startPoint = (Point) startValue;
        Point endPoint = (Point) endValue;

        float x = startPoint.getX() + (endPoint.getX() - startPoint.getX()) * fraction;
        float y = startPoint.getY() + (endPoint.getY() - startPoint.getY()) * fraction;

        return new Point(x,y);
    }
}

 private void animStart() {
        final MyView myView = findViewById(R.id.myview);
        Point start = new Point(30, 30);
        Point end = new Point(500, 500);
        ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointEvaluator(), start, end);
        valueAnimator.setDuration(5000);
        valueAnimator.setRepeatCount(100);
        valueAnimator.setRepeatMode(ValueAnimator.REVERSE);

        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Point point = (Point) animation.getAnimatedValue();

                myView.setX(point.getX());
                myView.setY(point.getY());
                myView.invalidate();

            }
        });
        valueAnimator.start();
    }

从上面的例子上看,实际还是对x和y的值进行模拟。需要自己定义TypeEvaluator,对值按照百分比进行估算。

ObjectAnimator
原理:直接对对象的属性值进行修改,从而实现动画效果,底层实现是基于ValueAnimator。

  private void animStart1() {
        //第一个值是执行动画的对象  第二个值是执行对象要改变的属性  第三和第四个值是初始值到结束值
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(btn,"translationX", 0, 1080);
        //原理 首先估值器不断的改变值
        //找到translationX 的set的方法不断的设置值
        //调用requestLayout来改变值Button的布局
        objectAnimator.setDuration(5000);
        objectAnimator.start();
    }

从上面的例子可以看出来,其实很容易的实现自定义属性主要有两种方式,一种可以定义属性,添加get和set方法,另外一种是通过一个包装类来实现类似效果。
先看第一种实现。

  private void animStart2() {
        MyView2 myView2 = findViewById(R.id.myview2);
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(myView2, "angle", 0, 360);
        objectAnimator.setDuration(5000);
        objectAnimator.start();
    }

public class MyView2 extends View {

    private Paint mCirclePaint;
    private Paint mArcPaint;
    private float angle;
    private RectF mRectF;


    public MyView2(Context context) {
        this(context, null);
    }

    public MyView2(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, -1);
    }

    public MyView2(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mCirclePaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mCirclePaint.setStrokeWidth(2.0f);
        mCirclePaint.setColor(Color.GRAY);

        mArcPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mArcPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mArcPaint.setStrokeWidth(2.0f);
        mArcPaint.setColor(Color.RED);

        mRectF = new RectF(0, 0, 200, 200);
    }

    public float getAngle() {
        return angle;
    }

    public void setAngle(float angle) {
        this.angle = angle;
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawCircle(mRectF.centerX(), mRectF.centerY(), mRectF.height() / 2, mCirclePaint);
        canvas.drawArc(mRectF, 180, angle, true, mArcPaint);
    }
}

还有一种通过包装类来实现,比如我想设置Button宽度的动画。代码如下

public class ViewWrapper {

    private View mTarget;
    private int width;

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
        mTarget.getLayoutParams().width = width;
        mTarget.requestLayout();

    }

    public ViewWrapper(View mTarget) {
        this.mTarget = mTarget;
    }
}

  private void animStart3() {
        ViewWrapper viewWrapper = new ViewWrapper(btn);
        ObjectAnimator objectAnimator = ObjectAnimator.ofInt(viewWrapper, "width", btn.getWidth(), 800);
        objectAnimator.setDuration(5000);
        objectAnimator.start();
    }

ObjectAnimator 和 ValueAnimator 区别
通过上面的例子可以知道,ObjectAnimator的实现底层就是ValueAnimator,ObjectAnimator的使用更加简单,可以直接设置属性开启动画并不需要其他额外操作。但是ValueAnimator还需要监听更新进度添加监听addUpdateListener(),根据值的不同,来实现动画。

插值器
作用:设置属性值从初始值过渡到结束值的变化规律,速度等,实现非线性的动画效果。
可以实现Interpolator 接口,实现getInterpolation的方法,返回fraction,估值器用于计算的百分比。

估值器
通过插值器的fraction,开始值和结束值,来计算出当前具体属性值。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值