标签:告诉 hit fse raw strong hold float upd 不同
android动画总共分为三种逐帧动画、补间动画、属性动画。
逐帧动画:主要就是将几张图片放在一起播放形成动画。
补间动画:补间动画还是比较局限的,能实现view的旋转、横竖拉伸、横竖平移、透明度等简单的变化。
由于android速度发展之快,原有的两种动画已经不能满足我们的需求,所以android在3.0版本推出了一个高大上的动画效果,属性动画。
TypeEvaluator的动画效果。那么下面我们进入正题。
三、objectAnimator和valueAnimator的简单用法
1、其实这两个动画先介绍哪两个都无所谓,但由于objectAnimatorValueAnimator的子类,那我们就先编写一个ValueAnimator的例子,之后再去扩展ObjectAnimator下面看代码:
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0.0f,360.0f); valueAnimator.setDuration(1000); valueAnimator.setTarget(imSimpleValueanimactionIcon); //这个地方是一定要设置的 不然不知道是哪个对象的 设置是哪个对象使用此动画 valueAnimator.start(); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { imSimpleValueanimactionIcon.setRotationY((Float)animation.getAnimatedValue()); } });
此段代码主要就是实现了一个功能,那就是imSimpleValueanimactionIcon这个View的旋转,首先我们去创建一个ValueAnimator的对象,创建ValueAnimator的方法有很多ofFloat是设置动画执行的开始和结束的float类型的值,0.0f为开始360f为结束,还有很多方法,ofInt、ofObject等。用法都是大同小异。在穿件对象之后,我们又去通过setDuration设置了动画执行的时间,ms是时间单位。然后我们去设置了这个动画要在哪个对象上面执行,调用了setTarget方法。最后设置了valueAnimator的开始,不过ValueAnimator并不知道我们设置的值需要执行在view的哪个属性上面,所以我们 需要监听动画的执行过程,通过获取执行过程中的值去设置view属性,这样我们通过addUpdateListener来获取动画执行到当前的值,animation.getAnimatedValue()此方法可以获取动画执行到当下的值是多少,一定是一个我们设置的值的中间数。然后我们通过设置旋转Y的角度去设置一下view的属性就可以实现动画效果了。
看完此段代码我们会想到去监听动画的值有些麻烦,也就是因为有这样麻烦的思想我们也就进入了ObjectAnimator,
ObjectAnimator是不需要监听动画执行过程中的值的,因为系统会自动为我们设置下面看代码:
ObjectAnimator animator = ObjectAnimator.ofFloat(view,"rotation",0.0f,360f); //这个rotation是系统内置的 animator.setDuration(1000); animator.start();
是不是简单了很多,这也是ObjectAnimator的一个优势,编写简单,不过理解相对繁琐一点,下面解释代码,首先我们还是通过老方法创建ObjectAnimator对象,创建对象的方法和ValueAnimator的方法几本相同,不过参数有些不同,我解释一下参数,第一个参数的意思是动画执行的对象,第二个参数是动画要操作的属性,这个属性系统定义了一些
基本上可以实现和补间动画相同的效果,不过我们也可以在view中自己定义一个属性,不过此属性一定要有getter和setter方法,如果没有这两个方法动画会实现不了,我们可以自定义一个color来改变颜色,在最后我们讲一个自定义属性的ObjectAnimator动画。执行程序我们会看到view旋转的效果。
animName.addListener(new AnimatorListener() { @Override public void onAnimationStart(Animator animation) { //动画的开始调用 } @Override public void onAnimationRepeat(Animator animation) { //动画重复执行调用 } @Override public void onAnimationEnd(Animator animation) { //动画的结束调用 } @Override public void onAnimationCancel(Animator animation) { //动画取消执行调用 } });
AnimatorSet animSet = new AnimatorSet();animSet.play(valueAnimator1).with(objectAnimator1); //一起播放 animSet.play(valueAnimator2).after(objectAnimator2); //之后播放 animSet.play(valueAnimator3).before(objectAnimator3); //之前播放 animSet.setDuration(5000); animSet.start();
从代码中我们可以看出来可以设置三种播放方式,其实每个AnimatorSet都可以设置很多play和with,但是不要吧所有的play和with都写在一个语句中,这样会造成系统的混乱。
PropertyValuesHolder X = PropertyValuesHolder.ofFloat("alpha", 1f, 0f, 1f); PropertyValuesHolder Y = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f); PropertyValuesHolder Z = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f); ObjectAnimator.ofPropertyValuesHolder(view, X, Y,Z).setDuration(1000).start();
ballView.animate().alpha(0).setDuration(5000).setInterpolator(new AndyaInterpolator());
//仅此一行代码就可以了
public interface TimeInterpolator { /** * Maps a value representing the elapsed fraction of an animation to a value that represents * the interpolated fraction. This interpolated value is then multiplied by the change in * value of an animation to derive the animated value at the current elapsed animation time. * * @param input A value between 0 and 1.0 indicating our current point * in the animation where 0 represents the start and 1.0 represents * the end * @return The interpolation value. This value can be more than 1.0 for * interpolators which overshoot their targets, or less than 0 for * interpolators that undershoot their targets. */ float getInterpolation(float input);
package com.transfar.andya.propertyanimactiondemo.TimeInterpolatorClass; import android.animation.TimeInterpolator; /** * Created by andYa on 2017/1/7. */ public class AndYaTimeInterpolator implements TimeInterpolator{ @Override public float getInterpolation(float input) { return (float) (Math.tan((input * 2 - 1) / 4 * Math.PI)) / 2.0f + 0.5f; } }
public interface TypeEvaluator<T> { /** * This function returns the result of linearly interpolating the start and end values, with * <code>fraction</code> representing the proportion between the start and end values. The * calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>, * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>, * and <code>t</code> is <code>fraction</code>. * * @param fraction The fraction from the starting to the ending values * @param startValue The start value. * @param endValue The end value. * @return A linear interpolation between the start and end values, given the * <code>fraction</code> parameter. */ public T evaluate(float fraction, T startValue, T endValue); }
/** * Created by andYa on 2017/1/6. */ public class Point { private float Y; private float X; public Point(float X,float Y){ this.X = X; this.Y = Y; } public float getY() { return Y; } public float getX() { return X; } public void setY(float y) { Y = y; } public void setX(float x) { X = x; } }entry我们定义完成了,那么我们就去自定义一下view,这个view我们只要定义一个画笔,然后去ondraw就可以了
/** * Created by andYa on 2017/1/6. */ public class BallView extends View { public static final float RADIUBALL = 30f; public Point currentPoint; private Paint mPaint; public BallView(Context context) { super(context); } public BallView(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setColor(Color.BLACK); } public BallView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public void onDraw(Canvas canvas){ if(currentPoint == null){ currentPoint = new Point(RADIUBALL, RADIUBALL); drawCricle(canvas); }else{ drawCricle(canvas); } } private void drawCricle(Canvas canvas){ float x = currentPoint.getX(); float y = currentPoint.getY(); canvas.drawCircle(x,y,RADIUS,mPaint); } }此段代码我们首先初始化了一个画笔,然后设置为黑色,然后我们又设置了半径currentPoint这个点就是给外界暴露的一个点,如果这个点为空,那我们就先给这个点赋上初始值,如果不为空我们就会ondraw()这个点,在动画改变点的时候我们一定要去调用invalidate()这个方法不然不会重绘的。下面我们就看一下最关键的地方TypeEvaluator:
public class PorpertyTypeEvaluator implements TypeEvaluator{ @Override public Object evaluate(float fraction, Object startValue, Object endValue) { Point startPoint = (Point)startValue; Point endPoint = (Point)endValue; float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX()); float y = startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY()); Point point = new Point(x, y); return point; } }
//调用的局部代码:ValueAnimator valueAnimator = ValueAnimator.ofObject(new PorpertyTypeEvaluator(),new Point(0f,0f),new Point(300f,300f)); valueAnimator.setTarget(ballView); valueAnimator.setInterpolator(new AndYaTimeInterpolator()); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { ballView.currentPoint = (Point) animation.getAnimatedValue(); ballView.invalidate(); //这个地方一定要让小球重绘不然是没效果的 } });
从代码中我们可以看出来TypeEvaluator就是告诉你动画过渡阶段的每个值应该返回什么,从第一段代码中可以看出返回的就是fraction所对应的点的坐标,其实在第一节中介绍的offloat也是有TypeEvaluator属性的只不过系统默认加上去的,是FloatEvaluator他呈现给我们的就是平滑的过渡效果。那么第二段代码就是调用了,我们去监听动画的改变,如果动画有变化我们就去得到这个点,然后重绘小球,是不是很简单。
private String color; public String getColor() { return color; } public void setColor(String color) { this.color = color; mPaint.setColor(Color.parseColor(color)); invalidate(); }
public class ColorTypeEvaluator implements TypeEvaluator{ //这个typeevaluator就是返回当前的object所以此color就是返回fraction对应的颜色的值 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; } }
ObjectAnimator objectAnimator = ObjectAnimator.ofObject(ballView,"color",new ColorTypeEvaluator(),"#0000FF", "#FF0000"); objectAnimator.setTarget(ballView); objectAnimator.setDuration(5000); objectAnimator.start();调用也是非常方便的如果我们在加上
标签:告诉 hit fse raw strong hold float upd 不同
原文地址:http://blog.csdn.net/a49681109/article/details/54029840