主要内容包括两部分,首先是视图动画(也叫补间动画),其次是属性动画
属性动画优于视图动画的地方在于,视图动画只是改变动画的显示,而并非真正响应事件,而属性动画中包括主要的两部分,其一为ObjectAnimator,其二ValueAnimator,值得一提的是,ObjectAnimator继承于ValueAnimator,并且更加耀眼。如果你想要出发点击事件,然后进行动画,则需要选择属性动画。
对于ObjectAnimator而言,操作的属性需要具有get和set方法,至于一些没有get和set方法的属性,例如width,可以使用包装类的方式进行封装,具体展示如下demo。
对于ofInt或者ofFloat而言,之前有一种疑问,为什么这里总是以数值的形式表示,现在分析一下,认为关键在于属性值。对于这类动画的变化,实际是对属性值得变化,因此设置了该两种方法。
并且,我们经常在回调监听得过程中使用到animation.getAnimatedValue(),该方法获取的是完成度,实际上是一种百分制,而并非上述ofInt或者ofFloat中设置的数值变化。
在常见的ofFloat参数中,往往具有以下两种
第一种:PropertyValuesHolder propertyValuesHolder = PropertyValuesHolder.ofFloat("translationX", 300f);
第二种:PropertyValuesHolder propertyValuesHolder1 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
至于value位置的参数个数,可以看作是一种变化,即平移到300f的位置,或者是将X坐标从100%缩放到0然后再变回100%。
对于ValueAnimator而言,可以直接进行值的变换,但是相对于ObjectAnimator而言,还需要进一步手动去获取变化的值,并将其应用到部件的属性中,例如demo中展示的。
值得一提的是,lz在demo实验过程中遇到了一个问题,即在onCreate中无法获取到mButton控件的高度,查阅资料后发现,是由于View的空间是在onLayer后才能够获取到宽高,而View和Activity的生命周期并非一一绑定的,并且,在onResume中也无法获得,具体原因可以简单解释为View的绘制和布置执行完的时机在这些的后面。
如果想要在onCreate中或者onResume中获取得到控件的宽高,可以采用post的方式,在消息队列末尾加入一则任务,例如demo中展示的。
至于好多文章中提到的动画插值器,简单理解为变换加速度,使用起来也很简单,分为两种,一种是xml中直接加入该属性,另一种是在代码文件中new一类插值器,例如demo中展示的。
DEMO:
```
import androidx.appcompat.app.AppCompatActivity;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.TranslateAnimation;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "VALUEANIMATOR_LOG";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AnimView animView = findViewById(R.id.animView);
Button mButton = findViewById(R.id.button);
//wrapperAnim(mButton);
//translationXAnim(mButton);
//xmlAnim(animView);
//alphaAnim(animView);
//translateAnim(animView);
//setAnim(mButton);
valueAnim(mButton);
}
private void valueAnim(Button button) {
ValueAnimator animator = ValueAnimator.ofFloat(0, 400);
animator.setTarget(button);
animator.setDuration(2000).start();
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
Log.d(TAG, "valueAnim: the button`s height is" + button.getHeight());
}
});
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Float value = (Float) animation.getAnimatedValue();
Log.d(TAG, "onAnimationUpdate: " + value);
button.setWidth(value.intValue());
}
});
}
private void setAnim(Button Button) {
PropertyValuesHolder propertyValuesHolder = PropertyValuesHolder.ofFloat("translationX", 300f);
PropertyValuesHolder propertyValuesHolder1 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
PropertyValuesHolder propertyValuesHolder2 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
ObjectAnimator.ofPropertyValuesHolder(Button, propertyValuesHolder, propertyValuesHolder1, propertyValuesHolder2).setDuration(2000).start();
}
private void wrapperAnim(Button button) {
WrapperView wrapperView = new WrapperView(button);
ObjectAnimator objectAnimator = ObjectAnimator.ofInt(wrapperView, "width", 500);
//两种设置监听的方式,首先是new Animator.AnimatorListener(),需要对四个方法全部实现,然后是new AnimatorListenerAdapter()
//这个方法帮助我们空实现了所有的方法,所以我们只需要实现我们用得到的方法进行监听即可
/* objectAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});*/
objectAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
Toast.makeText(MainActivity.this,"this", Toast.LENGTH_SHORT).show();
}
});
objectAnimator.setDuration(5000);
objectAnimator.start();
}
private void translationXAnim(Button button) {
ObjectAnimator animator = ObjectAnimator.ofFloat(button, "translationX", 300);
animator.setDuration(3000);
animator.start();
}
private void setAnim(){
AnimationSet animationSet = new AnimationSet(true);
animationSet.setDuration(5000);
animationSet.addAnimation(new AlphaAnimation(0,1));
}
private void alphaAnim(AnimView animView) {
AlphaAnimation alphaAnimation = new AlphaAnimation(0,1);
alphaAnimation.setDuration(5000);
animView.startAnimation(alphaAnimation);
alphaAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
//动画开始的时候调用
}
@Override
public void onAnimationEnd(Animation animation) {
//动画结束的时候调用
}
@Override
public void onAnimationRepeat(Animation animation) {
//动画重新执行的时候调用
}
});
}
private void translateAnim(AnimView animView){
TranslateAnimation animation = new TranslateAnimation(0, 100, 0, 200);
animation.setDuration(5000);
animView.startAnimation(animation);
}
private void xmlAnim(AnimView animView) {
//使用AnimationUtils类的静态方法loadAnimation方法可以达到加载XML文件中的动画的目的
Animation animation = AnimationUtils.loadAnimation(this, R.anim.scaleanim);
animView.setAnimation(animation);
}
//包装类,可以拓展其他的属性,只要赋予其get和set方法就可以实现类似于translationX的形式。
private static class WrapperView{
private View mTarget;
public WrapperView() {
}
public WrapperView(View target) {
mTarget = target;
}
public int getWidth(){
return mTarget.getLayoutParams().width;
}
public void setWidth(int width){
mTarget.getLayoutParams().width = width;
mTarget.requestLayout();
}
}
}
```
未完待续 如有不对的地方请指出,不完善的在后续学习中会继续补充