本篇建议学习完各个动画单独文章后再学习。
在Android动画中,总共有两种类型的动画View Animation(视图动画)和Property Animator(属性动画);其中
-
View Animation包括Tween Animation(补间动画)和Frame Animation(逐帧动画);
-
Property Animator包括ValueAnimator和ObjectAnimation;
首先,直观上,他们有如下三点不同:
1、引入时间不同:View Animation是API Level 1就引入的。Property Animation是API Level 11引入的,即Android 3.0才开始有Property Animation相关的API。
2、所在包名不同:View Animation在包android.view.animation中。而Property Animation API在包 android.animation中。
3、动画类的命名不同:View Animation中动画类取名都叫XXXXAnimation,而在Property Animator中动画类的取名则叫XXXXAnimator
1、为什么引入Property Animator(属性动画)
我提出一个假设:请问大家,如何利用补间动画来将一个控件的背景色在一分钟内从绿色变为红色?这个效果想必没办法仅仅通过改变控件的渐入渐出、移动、旋转和缩放来实现吧,而这个效果是可以通过Property Animator完美实现的
这就是第一个原因:Property Animator能实现补间动画无法实现的功能
大家都知道,补间动画和逐帧动画统称为View Animation,也就是说这两个动画只能对派生自View的控件实例起作用;而Property Animator则不同,从名字中可以看出属性动画,应该是作用于控件属性的!正因为属性动画能够只针对控件的某一个属性来做动画,所以也就造就了他能单独改变控件的某一个属性的值!比如颜色!这就是Property Animator能实现补间动画无法实现的功能的最重要原因。
我们得到了第二点不同:View Animation仅能对指定的控件做动画,而Property Animator是通过改变控件某一属性值来做动画的。
假设我们将一个按钮从左上角利用补间动画将其移动到右下角,在移动过程中和移动后,这个按钮都是不会响应点击事件的。这是为什么呢?因为补间动画仅仅转变的是控件的显示位置而已,并没有改变控件本身的值。View Animation的动画实现是通过其Parent View实现的,在View被drawn时Parents View改变它的绘制参数,这样虽然View的大小或旋转角度等改变了,但View的实际属性没变,所以有效区域还是应用动画之前的区域;我们看到的效果仅仅是系统作用在按钮上的显示效果,利用动画把按钮从原来的位置移到了右下角,但按钮内部的任何值是没有变化的,所以按钮所捕捉的点击区域仍是原来的点击区域。(下面会举例来说明这个问题)
这就得到了第三点不同:补间动画虽能对控件做动画,但并没有改变控件内部的属性值。而Property Animator则是恰恰相反,Property Animator是通过改变控件内部的属性值来达到动画效果的。
2、举例说明补间动画的点击区域问题
我们做一个Domo,点击Button移动两个TextView,其中一个使用View Animation移动,另外一个使用Property Animator移动。
xml文件:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.05"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.023" />
<TextView
android:id="@+id/tv_view_animation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="View Animation!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.051"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.134" />
<TextView
android:id="@+id/tv_property_animator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Property Animator!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.577"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.133" />
</androidx.constraintlayout.widget.ConstraintLayout>
Activity代码:
package com.example.animclickdomo;
import androidx.appcompat.app.AppCompatActivity;
import android.animation.ObjectAnimator;
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView viewAnimation_tv = (TextView) findViewById(R.id.tv_view_animation);
TextView propertyAnimator_tv = (TextView) findViewById(R.id.tv_property_animator);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TranslateAnimation animation = new TranslateAnimation(
Animation.ABSOLUTE,0,Animation.ABSOLUTE,0,
Animation.ABSOLUTE,0,Animation.ABSOLUTE,500);
animation.setFillAfter(true);
animation.setDuration(1000);
viewAnimation_tv.startAnimation(animation);
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(
propertyAnimator_tv,"translationY",500);
objectAnimator.setDuration(1000);
objectAnimator.start();
}
});
viewAnimation_tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"clicked View Animation",Toast.LENGTH_SHORT).show();
}
});
propertyAnimator_tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"clicked Property Animator",Toast.LENGTH_SHORT).show();
}
});
}
}
运行后,点击Start前,点击两个TextView都可以显示对应的Toast,点击Start后两个TextView都移动了,这时候点击以后后的PropertyAnimatorTextView依然可以显示Toast,但点击移动后的ViewAnimationTextView就没有任何反应,只有点击移动前的位置才能显示Toast。
另外:再次点击Start按钮ViewAnimationTextView可以再次从开始位置移动,而PropertyAnimatorTextView却保持之前移动的位置不动。
Domo代码: