1.1 ValueAniamor的基本使用
1.1.1 为何要引入属性动画
- 属性动画是为了弥补视图动画的不足而设计的,能够实现补间动画无法实现的功能。
从属性动画的名字我们知道它应该是用于操作控件的属性的。
补间动画的一个缺点
当我们利用补间动画绘制一个矩形,并给它设置点击事件,然后将它从屏幕的左上角移动到右下角时,我们会发现当我门点击当前右下角的位置,并不会触发点击事件,而当我们点击左上角时却会触发点击事件。这说明补间动画虽然可以对控件作动画,但是并没有改变控件内部的属性值。而使用属性动画来是是实现这一点就很容易了。
1.1.2 ValueAnimator的简单使用
ValueAnimator不会对控件执行任何操作。只能给他设定值的变化,通过值的变化来实现渐变,缩放等等效果。
1.初步使用
(1). 创建ValueAnimator
ValueAnimator animator=ValueAnimator.ofInt(0,400);
animator.setDuration(1000);
animator.start();
(2)添加监听事件
ValueAnimator animator=ValueAnimator.ofInt(0,400);
animator.setDuration(1000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
@Override
public void inAnimationUpdate(ValueAnimator animation){
int value=(Integer)animation.getAnimatedValue();
Log.d("value"+value);
}
});
animator.start();
使用addUpdateListener()函数添加一个监听事件,在函数传回的结果中,animation表示当前ValueAnimator实例,通过animation.getAnimatedValue()函数得到当前值。这就是ValueAnimator,对指定值区间进行动画运算,总之:
ValueAniamtor 只负责对指定值区间进行动画运算
我们需要对运算过程进行监听,然后自己对控件执行动画操作
现在我们利用属性动画来实现补间动画平移的问题
在线性布局中添加以下代码:
<Button
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="start"
android:id="@+id/btn"/>
<TextView
android:id="@+id/tv"
android:background="#fff000"
android:text="Hello"
android:padding="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
java代码如下:
private TextView tv ;
private Button btn ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById (R.id.tv);
btn = (Button) findViewById(R.id.btn) ;
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
doAnimation();
}
});
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast. makeText(MainActivity . this,"clicked me ", Toast.LENGTH_SHORT ) . show ();
}
});
}
private void doAnimation() {
ValueAnimator animator=ValueAnimator.ofInt(0,300);
animator.setDuration(1000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int value=(Integer)valueAnimator.getAnimatedValue();
tv.layout(value,value,value+tv.getWidth(),value+tv.getHeight());
}
});
animator.start();
}
从最后的结果中知道,在控件动画结束后,是仍然可以响应点击事件。
1.1.3 ValueAnimator的常用函数
(1)ofInt()和OfFloat()
public static ValueAnimator ofInt(int ... values)
public static ValueAnimator ofFloat(float ... values)
这两个函数的参数都是可变长参数,传进去的参数列表就是动画的变化范围。
常用函数汇总:
//设置动画时长
ValueAnimator setDuration(long duration)
//获取valueAnimator运动时当前运动点的值
Object getAnimatedValue()
//开始动画
void start()
//设置循环次数
void setRepeatCount(int value)
//设置循环模式
void setRepeatMode(int value)
//取消动画
void cancel()
1.2 自定义插值器与Evaluator
与view Animation一样,ValueAnimator也可以设置插值器,而且还可以设置Evaluator
1.2.1 自定义插值器
先来查看以下LinearInterpolator的源码:
public class LinearInterpolator extends BaseInterpolator {
public LinearInterpolator() {
throw new RuntimeException("Stub!");
}
public LinearInterpolator(Context context, AttributeSet attrs) {
throw new RuntimeException("Stub!");
}
public float getInterpolation(float input) {
throw new RuntimeException("Stub!");
}
}
public interface Interpolator extends TimeInterpolator {
}
public abstract class BaseInterpolator implements Interpolator {
public BaseInterpolator() {
throw new RuntimeException("Stub!");
}
}
LinearInterpolator继承于BaseInterpolator,BaseInterPolator继承于Interpolator,Interpolator继承于TimeInterpolator
查看TimeInterpolator如下:
public interface TimeInterpolator {
float getInterpolation(float var1);
}
它里面只有一个getInterpolation(float input)函数
- 参数input:input参数时float类型,它的取值范围为0~1,表示当前动画的进度,取0时表示动画刚开始,取1时表示动画结束,取0.5表示动画位于中间位置等等。
- 返回值:表示当前实际想要显示的进度,取值可以超过1,也可以小于0
看过插值器的具体实现我们来分析以下这个例子的具体实现。
ValueAnimator animator=ValueAnimator.ofInt(0,300);
animator.setDuration(1000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int value=(Integer)valueAnimator.getAnimatedValue();
}
});
animator.start();
其实先就如下公式:
当前的值=0+(300-0)*显示进度;
所以自定义插值器我们只需要是实现TimeInterpolator接口就可以了
public class MyInterpolator implements TimeInterpolator{
@Override
public float getInterpolation(float input){
return 1-input;//返回数学公式,数学公式决定了插值器的效果
}
}
使用时:
animator.setInterpolator(new MyInterpolator());
1.2.2 Evaluator
改图讲述了从定义动画的数值区间到AnimatorUpdateListener中得到当前动画所对应数值的整个过程。
(1)ofInt(0,400):表示指定动画的数值区间,从0到400
(2)插值器:表示动画开始后,通过插值器会返回当前动画进度所对应的数值进度,但这个数值是以小数表示的
(3)Evaluator:我们通过监听器拿到的是当前动画所对应的具体数值,而不是用小数表示的数值。所以必须有一个地方会根据当前的数值进度将其转换为对应的数值,这个地方就是Evaluator,用于将插值器返回的数值进度转换为对应的数值。
(4)监听器返回:通过在AnimatorUpdateListener监听器中使用animation.getAnimateValue()函数拿到Evaluator中返回的数值。