Android动画之ValueAnimator用法和自定义估值器

2024-05-06 13:48

本文主要是介绍Android动画之ValueAnimator用法和自定义估值器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

动画入门和进阶文章列表:

Animation动画概述和执行原理
Android动画之补间动画TweenAnimation
Android动画之逐帧动画FrameAnimation
Android动画之插值器简介和系统默认插值器
Android动画之插值器Interpolator自定义
Android动画之视图动画的缺点和属性动画的引入
Android动画之ValueAnimator用法和自定义估值器
Android动画之ObjectAnimator实现补间动画和ObjectAnimator自定义属性
Android动画之ObjectAnimator中ofXX函数全解析-自定义Property,TypeConverter,TypeEvaluator
Android动画之AnimatorSet联合动画用法
Android动画之LayoutTransition布局动画
Android动画之共享元素动画
Android动画之ViewPropertyAnimator(专用于view的属性动画)
Android动画之Activity切换动画overridePendingTransition实现和Theme Xml方式实现
Android动画之ActivityOptionsCompat概述
Android动画之场景变换Transition动画的使用
Android动画之Transition和TransitionManager使用
Android动画之圆形揭露动画Circular Reveal

1 ValueAnimator和估值器简介

属性动画从API11 开始提供,动画实现主要依靠ValueAnimator和ObjectAnimator两个类,类,属性动画所在包为android.animation.Animator,和补间动画有明显区别,补间动画在android.view.animation包目录下,也说明了属性动画不单单作用于view。

ValueAnimator是属性动画中重要且最基本的类,ObjectAnimator内部也是借助ValueAnimator实现的。ValueAnimator直接子类有两个ObjectAnimator和TimeAnimator。

ValueAnimator是数值从初始值逐渐变化到结束值,无法直接作用于对象,只能通过设置动画监听,获取动画过程中的过渡值,然后设置对象的属性就可以实现动画。默认插值器为AccelerateDecelerateInterpolator,插值器只是动画执行的快慢的控制,控制具体动画过程中获取的值是通过估值器Evaluator来实现的。

ValueAnimator可以利用XML文件生成和java代码生成ValueAnimator类两种方式实现动画。

2 代码方式生成ValueAnimator

ValueAnimator初始化函数:

  • ValueAnimator.ofInt(int … values)//处理整形参数
  • ValueAnimator.ofFloat(float … values)//处理浮点型
  • ValueAnimator. ofArgb(int… values) //处理颜色
  • ValueAnimator.ofObject(TypeEvaluator evaluator, Object… values)//处理object对象,需要自定义估值器
  • ValueAnimator.ofPropertyValuesHolder(PropertyValuesHolder… values) //处理PropertyValuesHolder

ValueAnimator使用过程:

  • 第一步:利用上面的函数生成ValueAnimator对象,
  • 第二步:设置动画的监听, addUpdateListener(ValueAnimator.AnimatorUpdateListener listener)
  • 第三第:四步利用添加的监听函数获取当前动画的值,getAnimatedValue()
  • 第四步:设置给View,实现动画

属性动画一般用代码生成(因为属性值无法写死在代码中,一般需要动态获取),所以本篇主要讲解代码生成方式,XML方式会提一下使用过程。

3 XML方式生成属性动画

XML生成属性动画三种标签:

  • : 对应ValueAnimator
  • : 对应ObjectAnimator
  • : 对应AnimatorSet
    通用属性设置和补间动画类似,本篇主要讲解ValueAnimator,所以标签主要讲解。
    举例:
    定义XML文件
<animator xmlns:android="http://schemas.android.com/apk/res/android"android:duration="1000" //动画持续时长android:valueFrom="1" //开始值android:valueTo="0"  //结束值android:valueType="floatType" //定义类型为float,相当于调用ValueAnimator.ofFloat()android:repeatCount="1" //重复次数android:repeatMode="reverse" //重复模式 />

API23 之后还可以利用PropertyValuesHolder和keyframe实现

<animator xmlns:android="http://schemas.android.com/apk/res/android"android:duration="1000"android:repeatCount="1"android:repeatMode="reverse"><propertyValuesHolder><keyframe android:fraction="0" android:value="1"/><keyframe android:fraction=".2" android:value=".4"/><keyframe android:fraction="1" android:value="0"/></propertyValuesHolder>
</animator>

利用AnimatorInflater加载上面定义的xml文件,生成Animator实例

Animator animator = AnimatorInflater.loadAnimator(context, R.animator.antorXML); 
//如果是ObjectAnimator设置动画对象,如果是ValueAnimator则不需要设置target
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {float name = (float) animation.getAnimatedValue();}});animator.setTarget(view); animator.start(); 

xml具体使用步骤总结:

  • 第一步利用XML动画文件和AnimatorInflater生成ValueAnimator对象
  • 第二步设置动画监听
  • 第三步获取监听的动画值
  • 第四步设置给view,执行动画

4 ValueAnimator代码方式详解

属性动画最好用代码实现,所以这篇文章也主要侧重代码实现。ValueAnimator无法像ObjectAnimator一样直接作用于对象,只能通过添加监听,获取动画过程之,然后手动设置给对象改变对象的属性。

4.1 ValueAnimator.ofInt(int … values)

values可以有多个值,ofInt作用是从初始值(参数中的第一个)以整数形式过渡到结束值,如果参数有多个,那就是从初始值过渡到第二个参数,然后从第二个参数过渡到第三个参数,后面以此类推。

mBtn = findViewById(R.id.btn);
imageView = findViewById(R.id.imageview);
valueAnimator = ValueAnimator.ofInt(1, 10);
valueAnimator.setDuration(1000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {int data = (int) animation.getAnimatedValue();System.out.println("========getAnimatedValue========="+data);}
});valueAnimator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationCancel(Animator animation) {super.onAnimationCancel(animation);}@Overridepublic void onAnimationEnd(Animator animation) {super.onAnimationEnd(animation);}@Overridepublic void onAnimationRepeat(Animator animation) {super.onAnimationRepeat(animation);}@Overridepublic void onAnimationStart(Animator animation) {super.onAnimationStart(animation);}@Overridepublic void onAnimationPause(Animator animation) {super.onAnimationPause(animation);}@Overridepublic void onAnimationResume(Animator animation) {super.onAnimationResume(animation);}
});
mBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (valueAnimator.isRunning()){valueAnimator.cancel();}valueAnimator.start();}
});

输出结果:
ofInt函数,获取到的值都是整形。
getAnimatedValue=1
getAnimatedValue=1
getAnimatedValue=1
getAnimatedValue=2
getAnimatedValue=4
getAnimatedValue=6
getAnimatedValue=8
getAnimatedValue=9
getAnimatedValue=9
getAnimatedValue=10

前面我们说了除了插值器,属性动画还用到了估值器Evaluator,但是使用ofInt时我们却没有设置估值器,为什么呢?
通过setEvaluator函数上上面的注释,可以知道当使用ofInt,ofFLoat时系统会自动根据startValue和endValue给动画指定估值器。
使用ofInt是使用的估值器是IntEvaluator,使用ofFloat是使用的估值器是FloatEvaluator。

分析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函数,evaluate三个参数的意义:
fraction:动画运行了多久,[0-1]的规范化数据,如果设置duration为1000ms,达到100ms时,fraction值为0.1,200ms为0.2。
startvalue:开始变化的值,
endValue:变化结束的值。

TypeEvaluator的evaluate函数返回值为(int)(startInt + fraction * (endValue - startInt)),
很简单就是开始值加上动画运行的时间乘以(结束值减去开始值)。

ofFloat代码举例:
ofFloat和onInt用法相同,只是数值精度不同,不再单独讲解,举个例子:

valueAnimator = ValueAnimator.ofFloat(1,0.5f);
valueAnimator.setDuration(1000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {float data = (float) animation.getAnimatedValue();Matrix matrix = new Matrix();matrix.setScale(data,data);//ImageView要支持matrix,需要设置ImageView的ScaleType为matriximageView.setImageMatrix(matrix);}
});

在这里插入图片描述

4.2 ofArgb 颜色渐变

ofArgb是api21提供的新方法,可以帮助我们实现颜色的渐变:

public static ValueAnimator ofArgb(int... values) {ValueAnimator anim = new ValueAnimator();anim.setIntValues(values);anim.setEvaluator(ArgbEvaluator.getInstance());return anim;
}

ofArgb内部利用ArgbEvaluator估值器计算动画运行期间的过渡颜色,所以颜色过渡的算法一定在ArgbEvaluator的evaluate方法中。

valueAnimator = ValueAnimator.ofArgb(Color.RED, Color.GREEN);
valueAnimator.setDuration(3000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {int data = (int) animation.getAnimatedValue();imageView.setBackgroundColor(data);textView.setBackgroundColor(data);}
});

在这里插入图片描述

4.3 ofObject()

方法:
ofObject(TypeEvaluator evaluator, Object… values)
参数说明:

  • evaluator:自定义估值器
  • values:开始结束对象
    ** ofObject处理对象,需要传入自定义估值器,告诉系统如何计算动画运行过程中的值。**
public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) {ValueAnimator anim = new ValueAnimator();anim.setObjectValues(values);anim.setEvaluator(evaluator);return anim;
}

需要自定义估值器,内部会设置自定义的估值器。

如何自定义估值器

** 上面已经分析了IntEvaluator的代码,下面直接举例定义一个既能改变颜色,又能改变view高度的估值器。**
首先定义用到的类,存储属性值:

public class HeightAndColor  {private int color;private int height;public int getColor() {return color;}public void setColor(int color) {this.color = color;}public int getHeight() {return height;}public void setHeight(int height) {this.height = height;}
}

定义估值器Evaluator
其中颜色渐变利用的RgbaEvaluator的算法。

public class HeightAndColorEvaluator implements TypeEvaluator<HeightAndColor> {@Overridepublic HeightAndColor evaluate(float fraction, HeightAndColor startValue, HeightAndColor endValue) {int startHeight = startValue.getHeight();int currHeight = (int) (startHeight + fraction * (endValue.getHeight() - startHeight));int currColor = getCurrRGBA(fraction, startValue.getColor(), endValue.getColor());HeightAndColor heightAndColor = new HeightAndColor();heightAndColor.setColor(currColor);heightAndColor.setHeight(currHeight);return heightAndColor;}public int getCurrRGBA(float fraction,int startValue,int endValue){int startInt =  startValue;float startA = ((startInt >> 24) & 0xff) / 255.0f;float startR = ((startInt >> 16) & 0xff) / 255.0f;float startG = ((startInt >>  8) & 0xff) / 255.0f;float startB = ( startInt        & 0xff) / 255.0f;int endInt = endValue;float endA = ((endInt >> 24) & 0xff) / 255.0f;float endR = ((endInt >> 16) & 0xff) / 255.0f;float endG = ((endInt >>  8) & 0xff) / 255.0f;float endB = ( endInt        & 0xff) / 255.0f;// convert from sRGB to linearstartR = (float) Math.pow(startR, 2.2);startG = (float) Math.pow(startG, 2.2);startB = (float) Math.pow(startB, 2.2);endR = (float) Math.pow(endR, 2.2);endG = (float) Math.pow(endG, 2.2);endB = (float) Math.pow(endB, 2.2);// compute the interpolated color in linear spacefloat a = startA + fraction * (endA - startA);float r = startR + fraction * (endR - startR);float g = startG + fraction * (endG - startG);float b = startB + fraction * (endB - startB);// convert back to sRGB in the [0..255] rangea = a * 255.0f;r = (float) Math.pow(r, 1.0 / 2.2) * 255.0f;g = (float) Math.pow(g, 1.0 / 2.2) * 255.0f;b = (float) Math.pow(b, 1.0 / 2.2) * 255.0f;return Math.round(a) << 24 | Math.round(r) << 16 | Math.round(g) << 8 | Math.round(b);}
}

使用定义的估值器:

HeightAndColor heightAndColor1 = new HeightAndColor();
heightAndColor1.setHeight(200);
heightAndColor1.setColor(Color.RED);
HeightAndColor heightAndColor2 = new HeightAndColor();
heightAndColor2.setHeight(400);
heightAndColor2.setColor(Color.GREEN);
valueAnimator = ValueAnimator.ofObject(new HeightAndColorEvaluator(), heightAndColor1, heightAndColor2);
valueAnimator.setDuration(3000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {HeightAndColor data = (HeightAndColor) animation.getAnimatedValue();textView.setBackgroundColor(data.getColor());ViewGroup.LayoutParams lp = textView.getLayoutParams();lp.height=data.getHeight();textView.setLayoutParams(lp);}
});

在这里插入图片描述

5 ofPropertyValuesHolder

PropertyValuesHolder类:
这个类持有一个属性名和对应的多个属性值,动画运行过程中会返回这种类型。ValueAnimator.ofInt(),ValueAnimator.ofFloat()等所有的函数内部都是把值存储到PropertyValuesHolder中。

ValueAnimator.ofInt函数

public static ValueAnimator ofInt(int... values) {ValueAnimator anim = new ValueAnimator();anim.setIntValues(values);return anim;
}//把值存入PropertyValuesHolder中
public void setIntValues(int... values) {if (values == null || values.length == 0) {return;}if (mValues == null || mValues.length == 0) {setValues(PropertyValuesHolder.ofInt("", values));} else {PropertyValuesHolder valuesHolder = mValues[0];valuesHolder.setIntValues(values);}// New property/values/target should cause re-initialization prior to startingmInitialized = false;
}

所以PropertyValuesHolder是Animator内部存储数据用的。

用法实例:

PropertyValuesHolder propertyValuesHolder1 = PropertyValuesHolder.ofFloat("str1", 1,2,3);
PropertyValuesHolder propertyValuesHolder2 = PropertyValuesHolder.ofFloat("str2", 4,5,6);
valueAnimator = ValueAnimator.ofPropertyValuesHolder(propertyValuesHolder1,propertyValuesHolder2);
valueAnimator.setDuration(1000);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {float name = (float) animation.getAnimatedValue("str1");float age = (float) animation.getAnimatedValue("str2");System.out.println("======1111========"+name+"   "+age);}
});

输出结果:
11111.0 4.0
1111
1.0 4.0
11111.034 4.034
1111
1.266 4.266
11111.5339999 4.534
1111
1.766 4.766
11112.0 5.0
1111
2.266 5.266
11112.534 5.534
1111
2.8 5.8
1111==3.0 6.0
Animation.getAnimatedValue(“propertyName”)就可以获取到对应的值。

PropertyValuesHolder的ofXX函数比较多:

ofFloat(Property<?, Float> property, float... values)
ofFloat(String propertyName, float... values)
ofInt(String propertyName, int... values)
ofInt(Property<?, Integer> property, int... values)
ofKeyframe(String propertyName, Keyframe... values)
ofKeyframe(Property property, Keyframe... values)
ofMultiFloat(String propertyName, float[][] values)
ofMultiFloat(String propertyName, TypeConverter<V, float[]> converter, TypeEvaluator<V> evaluator, V... values)
ofMultiFloat(String propertyName, Path path)
ofMultiFloat(String propertyName, TypeConverter<T, float[]> converter, TypeEvaluator<T> evaluator, Keyframe... values)
ofMultiInt(String propertyName, TypeConverter<V, int[]> converter, TypeEvaluator<V> evaluator, V... values)
ofObject(String propertyName, TypeConverter<PointF, ?> converter, Path path)
ofObject(String propertyName, TypeEvaluator evaluator, Object... values)
ofObject(Property<?, V> property, TypeConverter<T, V> converter, TypeEvaluator<T> evaluator, T... values)
。。。。。。

要讲解完所有的PropertyValuesHolder函数篇幅太大,后面会另开文章讲解。

这篇关于Android动画之ValueAnimator用法和自定义估值器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/964524

相关文章

#error用法

/* *检查编译此源文件的编译器是不是C++编译器 *如果使用的是C语言编译器则执行#error命令 *如果使用的是 C++ 编译器则跳过#error命令 */ #ifndef __cplusplus #error 亲,您当前使用的不是C++编译器噢! #endif #include <stdio.h> int main() {

ROS话题通信流程自定义数据格式

ROS话题通信流程自定义数据格式 需求流程实现步骤定义msg文件编辑配置文件编译 在 ROS 通信协议中,数据载体是一个较为重要组成部分,ROS 中通过 std_msgs 封装了一些原生的数据类型,比如:String、Int32、Int64、Char、Bool、Empty… 但是,这些数据一般只包含一个 data 字段,结构的单一意味着功能上的局限性,当传输一些复杂的数据,比如:

Eclipse+ADT与Android Studio开发的区别

下文的EA指Eclipse+ADT,AS就是指Android Studio。 就编写界面布局来说AS可以边开发边预览(所见即所得,以及多个屏幕预览),这个优势比较大。AS运行时占的内存比EA的要小。AS创建项目时要创建gradle项目框架,so,创建项目时AS比较慢。android studio基于gradle构建项目,你无法同时集中管理和维护多个项目的源码,而eclipse ADT可以同时打开

android 免费短信验证功能

没有太复杂的使用的话,功能实现比较简单粗暴。 在www.mob.com网站中可以申请使用免费短信验证功能。 步骤: 1.注册登录。 2.选择“短信验证码SDK” 3.下载对应的sdk包,我这是选studio的。 4.从头像那进入后台并创建短信验证应用,获取到key跟secret 5.根据技术文档操作(initSDK方法写在setContentView上面) 6.关键:在有用到的Mo

android一键分享功能部分实现

为什么叫做部分实现呢,其实是我只实现一部分的分享。如新浪微博,那还有没去实现的是微信分享。还有一部分奇怪的问题:我QQ分享跟QQ空间的分享功能,我都没配置key那些都是原本集成就有的key也可以实现分享,谁清楚的麻烦详解下。 实现分享功能我们可以去www.mob.com这个网站集成。免费的,而且还有短信验证功能。等这分享研究完后就研究下短信验证功能。 开始实现步骤(新浪分享,以下是本人自己实现

Android我的二维码扫描功能发展史(完整)

最近在研究下二维码扫描功能,跟据从网上查阅的资料到自己勉强已实现扫描功能来一一介绍我的二维码扫描功能实现的发展历程: 首页通过网络搜索发现做android二维码扫描功能看去都是基于google的ZXing项目开发。 2、搜索怎么使用ZXing实现自己的二维码扫描:从网上下载ZXing-2.2.zip以及core-2.2-source.jar文件,分别解压两个文件。然后把.jar解压出来的整个c

android 带与不带logo的二维码生成

该代码基于ZXing项目,这个网上能下载得到。 定义的控件以及属性: public static final int SCAN_CODE = 1;private ImageView iv;private EditText et;private Button qr_btn,add_logo;private Bitmap logo,bitmap,bmp; //logo图标private st

Android多线程下载见解

通过for循环开启N个线程,这是多线程,但每次循环都new一个线程肯定很耗内存的。那可以改用线程池来。 就以我个人对多线程下载的理解是开启一个线程后: 1.通过HttpUrlConnection对象获取要下载文件的总长度 2.通过RandomAccessFile流对象在本地创建一个跟远程文件长度一样大小的空文件。 3.通过文件总长度/线程个数=得到每个线程大概要下载的量(线程块大小)。

SQL Server中,isnull()函数以及null的用法

SQL Serve中的isnull()函数:          isnull(value1,value2)         1、value1与value2的数据类型必须一致。         2、如果value1的值不为null,结果返回value1。         3、如果value1为null,结果返回vaule2的值。vaule2是你设定的值。        如

时间服务器中,适用于国内的 NTP 服务器地址,可用于时间同步或 Android 加速 GPS 定位

NTP 是什么?   NTP 是网络时间协议(Network Time Protocol),它用来同步网络设备【如计算机、手机】的时间的协议。 NTP 实现什么目的?   目的很简单,就是为了提供准确时间。因为我们的手表、设备等,经常会时间跑着跑着就有误差,或快或慢的少几秒,时间长了甚至误差过分钟。 NTP 服务器列表 最常见、熟知的就是 www.pool.ntp.org/zo