android属性动画
来源:互联网 发布:什么是互联网大数据 编辑:程序博客网 时间:2024/06/10 06:07
一、概述
android动画总共分为三种逐帧动画、补间动画、属性动画。
逐帧动画:主要就是将几张图片放在一起播放形成动画。
补间动画:补间动画还是比较局限的,能实现view的旋转、横竖拉伸、横竖平移、透明度等简单的变化。
由于android速度发展之快,原有的两种动画已经不能满足我们的需求,所以android在3.0版本推出了一个高大上的动画效果,属性动画。
二、相关API:
ValueAnimator:属性动画的执行类,主要负责计算各个帧所对应的属性的值,可以处理动画的更新事件,它可以定义属性动画绝大部分的核心功能;
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实现动画的执行顺序
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
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());
//仅此一行代码就可以了
七、TimeInterpolator 时间插值
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);
可以看到如果实现测接口需要实现getInterpolation方法 此方法里面有一个input值,此值介于0到1之间,如果想改变动画的速度,就是通过此值实现的,input值的作用就是计算用户设置的值现在播放到什么程度的然后给予返回,TypeEvaluator的evaluate方法中的值就是通过input计算得到的,关于TypeEvaluator下节会介绍。
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; }}
此段代码是我从一个数学大神的手里拿到的,如果数学好的同学可以画一下此数学公式的x/y图,x为input,return为Y值,从斜率就可以看出来变化,如果你在你动画中设置valueAnimator.setInterpolator(new AndYaTimeInterpolator());
八、重写TyepEvaluator
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(); }
此段代码的setColor方法直接设置了画笔的颜色然后去重绘了一下。然后我们看一下第二点的实现,第二点的实现先对较为复杂一些,因为我们需要把传入的颜色编码进行转换,下面我贴上某位大神的代码:
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();调用也是非常方便的如果我们在加上
- Android动画--属性动画
- android动画 -- 属性动画
- Android动画-属性动画
- Android动画【属性动画】
- Android动画--属性动画
- android属性动画--布局动画
- Android 动画之属性动画
- Android中的动画,属性动画
- android-属性动画、视图动画
- Android动画之属性动画
- android动画 属性动画详解
- Android笔记----动画、属性动画
- Android动画之属性动画
- android 动画 之 属性动画
- Android动画之---属性动画
- Android动画之属性动画
- Android动画--属性动画--基础
- Android动画(三):属性动画
- Zookeeper(一)伪分布式安装
- Java虚拟机体系结构
- redis的dump.rdb备份数据
- jdbc动态条件查询防止sql注入的解决方案
- xml解析生成与解析
- android属性动画
- 操作与队列
- 告别2016迎接2017,分享一些第三方插件
- 5分钟DIY一个自定义单选框单选按钮
- NodeJS-crypto
- Spring源码剖析——依赖注入实现原理
- 软件架构概论
- android6.0下载文件路径设置
- Codeforces_607B:Zuma(区间DP)