Android属性动画

本文深入探讨了属性动画的核心概念,包括ObjectAnimator、ValueAnimator的使用方法,混合动画的实现,自定义属性动画以及ValueAnimator的高级应用。通过具体实例展示了如何在Android中创建平移、旋转、缩放、透明度变化等动画效果,并介绍了如何利用ValueAnimator实现更复杂的动画场景,如曲线动画。文章旨在为开发者提供全面的属性动画实践指南。
摘要由CSDN通过智能技术生成

属性动画

属性动画的核心主要是ObjectAnimator,ValueAnimator这几个对象的使用。下面对各个方法的使用进行介绍。

ObjectAnimator的使用:

一.单个动画的使用:

  • y轴旋转从0度旋转到360度
ObjectAnimator
    .ofFloat(imageView,"rotationY",0,360) 
    .setDuration(1000)
    .start();

这里写图片描述

  • x轴旋转从0度旋转到360度
ObjectAnimator
    .ofFloat(imageView,"rotationX",0,360) 
    .setDuration(1000)
    .start();

这里写图片描述

  • 宽度从原始长度到1.5倍长度
ObjectAnimator
    .ofFloat(imageView,"scaleX",1f,1.5f) 
    .setDuration(1000)
    .start();

这里写图片描述

  • 高度从原始长度到1.5倍长度
ObjectAnimator
    .ofFloat(imageView,"scaleY",1f,1.5f) 
    .setDuration(1000)
    .start();
  • 沿着x轴正方向从原始位置移动到相对于原始位置100px的位置
ObjectAnimator
    .ofFloat(imageView,"translationX",0,100) 
    .setDuration(1000)
    .start();
  • 沿着y轴正方向从原始位置移动到相对于原始位置100px的位置
ObjectAnimator
    .ofFloat(imageView,"translationY",0,100) 
    .setDuration(1000)
    .start();
  • 透明度从不透明到完全透明
ObjectAnimator
    .ofFloat(imageView,"alpha",1,0) 
    .setDuration(1000)
    .start();
  • 颜色改变动画,需要用到ObjectAnimator.ofArgb()方法(需要在API Level 21及以上的版本使用),如下是改变textView的背景颜色。
int startColor = 0xffff0000;
int endColor = 0xff00ff00;
ObjectAnimator
.ofArgb(textView,"backgroundColor",startColor,endColor)
.setDuration(1000)
.start();

二.混合动画的使用:

  • 针对一个View的混合动画主要使用到了PropertyValuesHolder,如果你想把scaleX和scaleY结合起来使用,那么需要构造两个对应的PropertyValuesHolder对象,最后再调用ObjectAnimator.ofPropertyValuesHolder,如下:
PropertyValuesHolder propertyValuesHolder1 = PropertyValuesHolder.ofFloat( "scaleX", 1f, 1.5f);
PropertyValuesHolder propertyValuesHolder2 = PropertyValuesHolder.ofFloat("scaleY", 1f, 1.5f);
ObjectAnimator.ofPropertyValuesHolder(imageView,propertyValuesHolder1
,propertyValuesHolder2)
.setDuration(3000)
.start();

这里写图片描述

  • AnimatorSet的使用
ObjectAnimator animator1 = ObjectAnimator.ofFloat(imageView,"scaleX",1f,4f,1f);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(imageView,"scaleY",1f,4f,1f);
AnimatorSet animSet = new AnimatorSet();
//animSet.play(animator1).with(animator2);//一起执行
animSet.play(animator1).after(animator2);//animator1在animator2执行完后执行
//animSet.play(animator1).before(animator2);//animator1在animator2前执行
//animSet.playTogether(animator1,animator2);一起执行
animSet.setDuration(2000);
animSet.start();

这里写图片描述

  • 两个属性的值随着Path进行变换(需要在API Level 21及以上的版本使用)
Path path = new Path();
//这边是一个矩形路径,前4个值是left,top,right,bottom值,最后一个参数表示动画的方向(CW代表顺时针和CCW代表逆时针)。
path.addRect(10,10,300,300,Path.Direction.CW);          ObjectAnimator.ofFloat(imageView,"translationX","translationY",path).setDuration(3000).start();

三.自定义属性动画:

  • 使用下面的API实现自定义的属性动画
ofFloat(T target, Property<T, Float> property, float... values)

实例:
自定义的CircleView:

public class CircleView extends View {
    private Paint paint;
    private float radius;

    public float getRadius() {
        return radius;
    }
    public void setRadius(float radius) {
        this.radius = radius;

    public CircleView(Context context) {
        super(context);
    }
    public CircleView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CircleView(Context context, AttributeSet attrs, int
       defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        if (paint == null) {
            paint = new Paint();
            paint.setColor(getResources().getColor(
            android.R.color.holo_red_light));
        }
        canvas.drawCircle(getWidth()/2, getHeight()/2, radius, 
            paint);
    }
}

动画执行代码:

Property property = new Property<CircleView, Float>(Float.class, "radius") {
    @Override
     public Float get(CircleView object) {
         return object.getRadius();
     }

    @Override
     public void set(CircleView object, Float value) {
                      object.setRadius(value);
     }
};
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(circleView, property, 10f,100f,10f);
objectAnimator.setRepeatCount(10);
objectAnimator.addUpdateListener(new  ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
                  circleView.invalidate();
    }
});
objectAnimator.setDuration(2000);
objectAnimator.start();

xml布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.lt.javatest.animal.AnimalActivity">
    <com.lt.javatest.animal.CircleView
        android:id="@+id/circleView"
        android:layout_centerInParent="true"
        android:layout_width="100dp"
        android:layout_height="100dp" />
    <Button
        android:id="@+id/scaleButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/circleView"
        android:layout_centerHorizontal="true"
        android:text="click" />
</RelativeLayout>

实例效果:
这里写图片描述

ValueAnimator的使用

ValueAnimator类是我们上面说到的ObjectAnimator的父类,阅读源码,我们可以发现ObjectAnimator动画最终是通过ValueAnimation实现的。下面就来说说ValueAnimator的使用。

  • 单个值变化 ,imageView沿着x轴从1移动到100,这边其实把ValueAnimator换成ObjectAnimator也是一样的效果,因为ObjectAnimator是ValueAnimator的子类。
ValueAnimator valueAnimator = ValueAnimator.ofFloat(1,100);
valueAnimator.setDuration(1000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
     @Override
      public void onAnimationUpdate(ValueAnimator animation) {
          imageView.setTranslationX((Float) animation.getAnimatedValue());
     }
 });
valueAnimator.start();
  • 多个值变化
PropertyValuesHolder property1 = PropertyValuesHolder.ofFloat("value1", 1,100);
PropertyValuesHolder property2 = PropertyValuesHolder.ofFloat("value2", 100, 200);
ValueAnimator valueAnimator = ValueAnimator
    .ofPropertyValuesHolder(property1, property2);
valueAnimator.setDuration(1000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
   @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        float value1 = (float) animation.getAnimatedValue("value1");
        float value2 = (float) animation.getAnimatedValue("value2");
        imageView.setTranslationX(value1);
        imageView.setTranslationY(value2);
    }
});
valueAnimator.start();
  • 使用setEvaluator(TypeEvaluator value)来计算AnimatedValue,实现高级的动画效果。
    示例: 电商类APP常用的一个动画场景,把商品加入购物车,商品呈曲线掉入购入车。
    源码地址:https://github.com/heheLT/AnimationBall
    效果图:
    这里写图片描述

主要代码:

/**
* 二阶赛贝尔曲线,由三个点确定一条曲线
*/
public void paoWuXian(final int[] startLocation, final int[] endLocation, final View
animalView, final View endView) {
   final float[] middle = new float[2];

   middle[0] = endLocation[0];//中间点的x,这边也可以取其他值
   middle[1] = startLocation[1];//中间点的y,这边也可以取其他值

   ValueAnimator valueAnimator = new ValueAnimator();
   valueAnimator.setDuration(1000);
   valueAnimator.setObjectValues(new PointF(endLocation[0], endLocation[1]));
   valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
   valueAnimator.setEvaluator(new TypeEvaluator<PointF>() {
      @Override
      public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
          PointF point = new PointF();
          //这边利用的是二阶贝塞尔曲线公式计算x,y
          point.x = (1 - fraction) * (1 - fraction) * startLocation[0] 
                      + 2 * fraction * (1 - fraction) * middle[0] 
                      + fraction * fraction * endLocation[0];
          point.y = (1 - fraction) * (1 - fraction) * startLocation[1] 
                      + 2 * fraction * (1 - fraction) * middle[1] 
                      + fraction * fraction * endLocation[1];
           return point;
      }
   });
   valueAnimator.start();
   valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
       @Override
       public void onAnimationUpdate(ValueAnimator animation) {
           PointF point = (PointF) animation.getAnimatedValue();
           animalView.setX(point.x);
           animalView.setY(point.y);
       }
   });
   valueAnimator.addListener(new ValueAnimator.AnimatorListener() {
       @Override
       public void onAnimationStart(Animator animation) {
       }
       @Override
       public void onAnimationEnd(Animator animation) {
           //抛物线动画结束后,进行缩放动画
           ValueAnimator valueAnimator = new ValueAnimator();
           valueAnimator.setDuration(400);
           valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
           valueAnimator.setObjectValues(1.0f, 0.8f);
           valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
               @Override
               public void onAnimationUpdate(ValueAnimator animation) {
                   float value = (float) animation.getAnimatedValue();
                   if (value > 0.9) {
                       endView.setScaleX(value);
                       endView.setScaleY(value);
                   } else {
                       endView.setScaleX(1.8f - value);
                       endView.setScaleY(1.8f - value);
                   }
               }
           });
           valueAnimator.start();
       }
       @Override
       public void onAnimationCancel(Animator animation) {
       }

       @Override
       public void onAnimationRepeat(Animator animation) {
       }
   });
}

ValueAnimator总结:

ValueAnimator其实是一个控制值变化的辅助类,我们设置了变化得起点,终点以及时间,这样ValueAnimator提供了一个值变化的监听接口,这样就可以拿到变化的值,然后设置到View上面,形成动画。我们可以通过setEvaluator(TypeEvaluator value)来计算AnimatedValue的值,实现自定义动画。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值