Android 属性动画使用(二)

首先扯点别的:晚上稍微跑了一会步,然后逛了超市,晚饭喝的南瓜粥,吃了一碗面条,今天不是太饿,现在正一边吃着葡萄一边学习,也是没谁了。

比如说,我们想要实现从0过渡到100,使用ValueAnimator 就可以这样写:

ValueAnimator va = ValueAnimator.ofInt(1, 00);
va.setDuration(3000);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator animation) {
             Log.e("tag", "value : " + animation.getAnimatedValue());
      }
});
va.start();

打印出来的结果就是从1到100;但是这是怎么实现的呢,这是因为系统内置了一个IntEvaluator(相当于一个计算器)来实现计算如何从动画的初始值过渡到结束值。

//IntEvaluator 的evaluate方法
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
   int startInt = startValue;
   //就返回初始值加上fraction乘上结束值减去初始值fraction变化范围0到1
   return (int)(startInt + fraction * (endValue - startInt));
}

ValueAnimator有一个ofObject方法,用来操作对象的动画。但是和ofInt或者ofFloat方法相比,ofObject没法内置一个Evaluator,因为对象不同,计算的方式也不一样,所以要自己实现一个继承自TypeEvaluator的Evaluator。

使用场景:自定义一个View,View中有一个Point()对象用来管理坐标,View在onDraw方法中根据Point()对象的坐标进行绘制,然后使用ValueAnimator来改变Poin对象的坐标值,那么自定义View就会实现动画效果。

//具有x,y两个属性和相应的get,set函数
public class MyPoint {
    private float x;

    private float y;

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

    public float getX() {
        return x;
    }

    public float getY() {
        return y;
    }
}

自定义PointEvaluator

public class PointEvaluator implements TypeEvaluator<MyPoint> {

    @Override
    public MyPoint evaluate(float fraction, MyPoint startValue, MyPoint endValue) {
    //改变x值
        float x = startValue.getX() + fraction * (endValue.getX() - startValue.getX());
        //改变y值
        float y = startValue.getY() + fraction * (endValue.getY() - startValue.getY());
        MyPoint point = new MyPoint(x, y);
        //返回一个新的Point对象,坐标已经改变了
        return point;
    }
}

新建一个PointAnimView 继承自View

public class PointAnimView extends View {

    public static final float RADIUS = 50f;  //point点的半径

    private MyPoint currentPoint;

    private Paint mPaint;

    public PointAnimView(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 MyPoint(RADIUS, RADIUS);
            drawCircle(canvas);
            startAnimation();
        } else {
            drawCircle(canvas);
        }
    }

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

    private void startAnimation() {
        MyPoint startPoint = new MyPoint(RADIUS, RADIUS);
        MyPoint endPoint = new MyPoint(getWidth() - RADIUS, getHeight() - RADIUS);
        ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                currentPoint = (MyPoint) animation.getAnimatedValue();
                invalidate();  
            }
        });
        anim.setDuration(5000);
        anim.start();
    }
}  

将PointAnimView 引入布局文件使用。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.hm.animationdemo.widget.PointAnimView
        android:id="@+id/point_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>

效果图

这里写图片描述

ObjectAnimator的高级用法

实现动态改变PointAnimView的颜色,那就得给PointAnimView添加color属性并提供相应的getColor方法和setColor方法,在setColor方法中改变View里面画笔的颜色,然后调用invalidate方法刷新视图,在绘制的时候,View的颜色就会发生变化

    private String color;  
  
    public String getColor() {  
        return color;  
    }  
  
    public void setColor(String color) {  
        this.color = color;  
        mPaint.setColor(Color.parseColor(color));  
        invalidate();  
    }  

ObjectAnimator的ofObject方法

//可以看到第三个参数是一个TypeEvaluator ,用来计算Object的属性,在这里就是我们的color如何变化,
//所以要重写一个TypeEvaluator来计算颜色的变化
public static ObjectAnimator ofObject(Object target, String propertyName,
            TypeEvaluator evaluator, Object... values)
            
//这个实现细节,就愉快的略过吧。
public class ColorEvaluator implements TypeEvaluator {  
  
    private int mCurrentRed = -1;  
  
    private int mCurrentGreen = -1;  
  
    private int mCurrentBlue = -1;  
  
    @Override  
    public Object evaluate(float fraction, Object startValue, Object endValue) {  
        String startColor = (String) startValue;  
        String endColor = (String) endValue;  
        int startRed = Integer.parseInt(startColor.substring(1, 3), 16);  
        int startGreen = Integer.parseInt(startColor.substring(3, 5), 16);  
        int startBlue = Integer.parseInt(startColor.substring(5, 7), 16);  
        int endRed = Integer.parseInt(endColor.substring(1, 3), 16);  
        int endGreen = Integer.parseInt(endColor.substring(3, 5), 16);  
        int endBlue = Integer.parseInt(endColor.substring(5, 7), 16);  
        // 初始化颜色的值  
        if (mCurrentRed == -1) {  
            mCurrentRed = startRed;  
        }  
        if (mCurrentGreen == -1) {  
            mCurrentGreen = startGreen;  
        }  
        if (mCurrentBlue == -1) {  
            mCurrentBlue = startBlue;  
        }  
        // 计算初始颜色和结束颜色之间的差值  
        int redDiff = Math.abs(startRed - endRed);  
        int greenDiff = Math.abs(startGreen - endGreen);  
        int blueDiff = Math.abs(startBlue - endBlue);  
        int colorDiff = redDiff + greenDiff + blueDiff;  
        if (mCurrentRed != endRed) {  
            mCurrentRed = getCurrentColor(startRed, endRed, colorDiff, 0,  
                    fraction);  
        } else if (mCurrentGreen != endGreen) {  
            mCurrentGreen = getCurrentColor(startGreen, endGreen, colorDiff,  
                    redDiff, fraction);  
        } else if (mCurrentBlue != endBlue) {  
            mCurrentBlue = getCurrentColor(startBlue, endBlue, colorDiff,  
                    redDiff + greenDiff, fraction);  
        }  
        // 将计算出的当前颜色的值组装返回  
        String currentColor = "#" + getHexString(mCurrentRed)  
                + getHexString(mCurrentGreen) + getHexString(mCurrentBlue);  
        return currentColor;  
    }  
  
    /** 
     * 根据fraction值来计算当前的颜色。 
     */  
    private int getCurrentColor(int startColor, int endColor, int colorDiff,  
            int offset, float fraction) {  
        int currentColor;  
        if (startColor > endColor) {  
            currentColor = (int) (startColor - (fraction * colorDiff - offset));  
            if (currentColor < endColor) {  
                currentColor = endColor;  
            }  
        } else {  
            currentColor = (int) (startColor + (fraction * colorDiff - offset));  
            if (currentColor > endColor) {  
                currentColor = endColor;  
            }  
        }  
        return currentColor;  
    }  
      
    /** 
     * 将10进制颜色值转换成16进制。 
     */  
    private String getHexString(int value) {  
        String hexString = Integer.toHexString(value);  
        if (hexString.length() == 1) {  
            hexString = "0" + hexString;  
        }  
        return hexString;  
    }  
  
}  

定义好了ColorEvaluator ,就可以改变颜色了,改变MyAinmView中的startAnimation方法,就可以实现在改变view的位置的同时改变view的颜色了。

 private void startAnimation() {
    MyPoint startPoint = new MyPoint(RADIUS, RADIUS);
    MyPoint endPoint = new MyPoint(getWidth() - RADIUS, getHeight() - RADIUS);
    ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            currentPoint = (MyPoint) animation.getAnimatedValue();
            invalidate();
        }
    });
    ObjectAnimator anim2 = ObjectAnimator.ofObject(this, "color", new ColorEvaluator(),
                "#0000FF", "#FF0000");
    AnimatorSet animSet = new AnimatorSet();
    animSet.play(anim).with(anim2);
    animSet.setDuration(5000);
    animSet.start();
}

效果如下
这里写图片描述

结尾:文章中的代码来自部分摘自郭霖老师的博客。是时候睡觉了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值