当前位置:网站首页>动画(其二)

动画(其二)

2022-08-11 05:22:00 hqhe260

属性动画

属性动画(Property Animation)

2.1 属性动画的简介

2.1.1 为什么要引入属性动画?

  • 补间动画功能比较单调,只有四种动画(透明度,旋转,倾斜和位移)
  • 补间动画针对的对象只是UI控件
  • 补间动画只是改变View的显示效果,不会去改变View的属性

eg:左边的按钮移到右边,但是此时的按钮其实还停留在左边,假如你去点右面的按钮,是不会触发按钮的点击事件的~

2.1.2 属性动画是什么?

  • Andoid 3.0引入,可以说是补间动画的增强版,不止可以实现四种动画效果,可以定义任何属性的变化;
  • 执行动画的对象不只是U控件。可以对任何对象执行动画(不管是否显示在屏幕上)
  • 属性动画通过对目标对象进行赋值来修改其属性,上面那个按钮问题就不存在了~

2.1.3 属性动画相关的API

API说明
Animator创建属性动画的基类,一般不会直接用,一般用他的两个子类!
ValueAnimator上面也说了,属性动画是通过不断地修改值来实现的,而初始值和结束值间的过度动画就是由该类来负责计算的。内部采用一种时间循环的机制来计算值与值之间的动画过度,我们只需将初始值以及结束值提供给该类,并告诉它动画所需时长,该类就会自动帮我们完成从初始值平滑过渡到结束值这样的效果!除此之外,该类还负责管理动画播放次数,播放模式,以及对动画设置监听器等!
ObjectAnimatorValueAnimator的子类,允许我们对指定对象的属性执行动画,用起来更加简单,实际中用得较多。当然某些场合下,可能还是需要用到ValueAnimator
AnimatorSetAnimator的子类,用于组合多个Animator ,并制定多个Animator按照次序播放,还是同时播放
Evaluator告诉动画系统如何从初始值过度到结束值,提供了下述几种Evaluator :
- IntEvaluator :用于计算int类型属性值的计算器
- FloatEvaluator :用于计算float类型属性值的计算器
- ArgbEvaluator :用于计算十六进制形式表示的颜色值的计算器
- TypeEvaluator :计算器的接口,我们可以实现该接口来完成自定义计算器

2.2 ValueAnimator简单使用

2.2.1 使用流程:

  1. 调用ValueAnimator的ofInt(),ofFloat()或ofObject()静态方法创建ValueAnimator实例
  2. 调用实例的setXxx方法设置动画持续时间,插值方式,重复次数等
  3. 调用实例的addUpdateListener添加AnimatorUpdateListener监听器,在该监听器中 可以获得ValueAnimator计算出来的值,你可以值应用到指定对象上
  4. 调用实例的**start()**方法开启动画! 另外我们可以看到ofInt和ofFloat都有个这样的参数:float/int… values代表可以多个值!

使用示例:

代码实现

布局文件:activity_main.xml,非常简单,四个按钮,一个ImageView

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/ly_root" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">

    <Button android:id="@+id/btn_one" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="动画1" />

    <Button android:id="@+id/btn_two" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="动画2" />

    <Button android:id="@+id/btn_three" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="动画3" />

    <Button android:id="@+id/btn_four" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="动画4" />

    <ImageView android:id="@+id/img_babi" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:background="@mipmap/img_babi" />

</LinearLayout>

接着到MainActivity.java, 首先需要一个修改View位置的方法,这里调用moveView()设置左边和上边的起始坐标以及宽高!

接着定义了四个动画,分别是:直线移动,缩放,旋转加透明,以及圆形旋转!

然后通过按钮触发对应的动画~

 private Button button, button2, button3, button4;
    private ImageView iv;
    private LinearLayout layout_root;
    private int height;
    private int width;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button = findViewById(R.id.button);
        button2 = findViewById(R.id.button2);
        button3 = findViewById(R.id.button3);
        button4 = findViewById(R.id.button4);
        layout_root = findViewById(R.id.layout_root);
        iv = findViewById(R.id.iv);

        //让图案上下水平移动
        button.setOnClickListener(new View.OnClickListener() {
    
            @Override
            public void onClick(View view) {
    
                width = layout_root.getWidth();
                height = layout_root.getHeight();
                ValueAnimator valueAnimator = ValueAnimator.ofInt(height, 0, height / 4, height / 2, height / 4 * 3, height);
                valueAnimator.setDuration(3000L);
                valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
    
                        // 轨迹方程 x = width / 2
                        int y = (Integer) animation.getAnimatedValue();
                        int x = width / 2;
                        moveView(iv, x, y);
                    }
                });
                valueAnimator.setInterpolator(new LinearInterpolator());
                valueAnimator.start();
            }
        });
        //对按钮进行缩放
        button2.setOnClickListener(new View.OnClickListener() {
    
            @Override
            public void onClick(View view) {
    
                final float scale = 0.5f;
                AnimatorSet scaleSet = new AnimatorSet();
                ValueAnimator valueAnimatorSmall = ValueAnimator.ofFloat(1.0f, scale);
                valueAnimatorSmall.setDuration(500);

                ValueAnimator valueAnimatorLarge = ValueAnimator.ofFloat(scale, 1.0f);
                valueAnimatorLarge.setDuration(500);

                valueAnimatorSmall.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
    
                        float scale = (Float) animation.getAnimatedValue();
                        iv.setScaleX(scale);
                        iv.setScaleY(scale);
                    }
                });
                valueAnimatorLarge.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
    
                        float scale = (Float) animation.getAnimatedValue();
                        iv.setScaleX(scale);
                        iv.setScaleY(scale);
                    }
                });

                scaleSet.play(valueAnimatorLarge).after(valueAnimatorSmall);
                scaleSet.start();
            }
        });

        //旋转的同时发生透明度变化
        button3.setOnClickListener(new View.OnClickListener() {
    
            @Override
            public void onClick(View view) {
    
                ValueAnimator b = ValueAnimator.ofInt(0,360);
                b.setDuration(1000L);
                b.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
    
                        int rovalue = (Integer) animation.getAnimatedValue();
                        iv.setRotation(rovalue);
                        float fraction = animation.getAnimatedFraction();
                        iv.setAlpha(fraction);

                    }
                });
                b.setInterpolator(new DecelerateInterpolator());
                b.start();
            }
        });

        //园型旋转
        button4.setOnClickListener(new View.OnClickListener() {
    
            @Override
            public void onClick(View view) {
    
                width = layout_root.getWidth();
                height = layout_root.getHeight();

                final int r=width/4;
                ValueAnimator valueAnimator02 =ValueAnimator.ofFloat(0,(float)(2.0f * Math.PI) );
                valueAnimator02.setDuration(1000);
                valueAnimator02.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    
                    @Override
                    public void onAnimationUpdate(ValueAnimator valueAnimator) {
    
                        float t=(Float) valueAnimator.getAnimatedValue();
                        int x=(int )(r * Math.sin(t) + width / 2);
                        int y=(int )(r * Math.cos(t) + height / 2);
                        moveView(iv,x,y);
                    }
                });

                valueAnimator02.setInterpolator(new DecelerateInterpolator());
                valueAnimator02.start();
            }
        });
    }

    //定义一个修改ImageView位置的方法
    private void moveView(View view, int rawx, int rawy) {
    
        int left = rawx - iv.getWidth();
        int top = rawy - iv.getHeight();
        int width = left + view.getWidth();
        int height = top + view.getHeight();
        view.layout(left, top, width, height);
    }
}

好的,使用的流程非常简单,先创建ValueAnimator对象,调用ValueAnimator.ofInt/ofFloat 获得,然后设置动画持续时间,**addUpdateListener**添加**AnimatorUpdateListener**事件监听, 然后使用参数**animation****getAnimatedValue**()获得当前的值,然后我们可以拿着这个值 来修改View的一些属性,从而形成所谓的动画效果,接着设置setInterpolator动画渲染模式, 最后调用start()开始动画的播放


##  2.3 ObjectAnimator简单使用



比起ValueAnimatorObjectAnimator显得更为易用,通过该类我们可以**直接** **对任意对象的任意属性进行动画操作**!没错,是任意对象,而不单单只是View对象, 不断地对对象中的某个属性值进行赋值,然后根据对象属性值的改变再来决定如何展现 出来!比如为TextView设置如下动画: **ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f);**
这里就是不断改变alpha的值,从1f - 0f,然后对象根据属性值的变化来刷新界面显示,从而 展现出淡入淡出的效果,而在TextView类中并没有alpha这个属性,ObjectAnimator内部机制是: **寻找传输的属性名对应的get和set方法~,而非找这个属性值!** 不信的话你可以到TextView的源码里找找是否有alpha这个属性! 好的,下面我们利用ObjectAnimator来实现四种补间动画的效果吧~

**运行效果图**[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BBeszcRe-1659004693138)(MD文档.assets/48695379.jpg)]

**代码实现**:

布局直接用的上面那个布局,加了个按钮,把ImageView换成了TextView,这里就不贴代码了, 直接上**MainActivity.java**部分的代码,其实都是大同小异的~

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main5);
    bindViews();
    initAnimator();
}

private void bindViews() {
    ly_root = (LinearLayout) findViewById(R.id.ly_root);
    btn_one = (Button) findViewById(R.id.btn_one);
    btn_two = (Button) findViewById(R.id.btn_two);
    btn_three = (Button) findViewById(R.id.btn_three);
    btn_four = (Button) findViewById(R.id.btn_four);
    btn_five = (Button) findViewById(R.id.btn_five);
    tv_pig = (TextView) findViewById(R.id.tv_pig);

    height = ly_root.getHeight();
    btn_one.setOnClickListener(this);
    btn_two.setOnClickListener(this);
    btn_three.setOnClickListener(this);
    btn_four.setOnClickListener(this);
    btn_five.setOnClickListener(this);
    tv_pig.setOnClickListener(this);
}

//初始化动画
private void initAnimator() {
    animator1 = ObjectAnimator.ofFloat(tv_pig, "alpha", 1f, 0f, 1f, 0f, 1f);
    animator2 = ObjectAnimator.ofFloat(tv_pig, "rotation", 0f, 360f, 0f);
    animator3 = ObjectAnimator.ofFloat(tv_pig, "scaleX", 2f, 4f, 1f, 0.5f, 1f);
    animator4 = ObjectAnimator.ofFloat(tv_pig, "translationY", height / 8, -100, height / 2);
}

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.btn_one:
            animator1.setDuration(3000l);
            animator1.start();
            break;
        case R.id.btn_two:
            animator2.setDuration(3000l);
            animator2.start();
            break;
        case R.id.btn_three:
            animator3.setDuration(3000l);
            animator3.start();
            break;
        case R.id.btn_four:
            animator4.setDuration(3000l);
            animator4.start();
            break;
        case R.id.btn_five:
            //将前面的动画集合到一起~
            animSet = new AnimatorSet();
            animSet.play(animator4).with(animator3).with(animator2).after(animator1);
            animSet.setDuration(5000l);
            animSet.start();
            break;
        case R.id.tv_pig:
            Toast.makeText(MainActivity.this, "不愧是你", Toast.LENGTH_SHORT).show();
            break;
    }
}

}


### 2.4 使用XML来编写动画

使用XML来编写动画,画的时间可能比Java代码长一点,但是重用起来就轻松很多! 对应的XML标签分别为:<**animator**><**objectAnimator**><**set**> 相关的属性解释如下:

- **android:ordering**:指定动画的播放顺序:sequentially(顺序执行),together(同时执行)
- **android:duration**:动画的持续时间
- **android:propertyName**="x":这里的x,还记得上面的"alpha"吗?加载动画的那个对象里需要 定义getx和setx的方法,objectAnimator就是通过这里来修改对象里的值的!
- **android:valueFrom**="1" :动画起始的初始值
- **android:valueTo**="0" :动画结束的最终值
- **android:valueType**="floatType":变化值的数据类型

**使用例子如下**:

animator/property_animator.xml

```xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="together" >

    <objectAnimator
        android:duration="3000"
        android:propertyName="translationX"
        android:valueFrom="-500"
        android:valueTo="0"
        android:valueType="floatType" >
    </objectAnimator>
    <objectAnimator
        android:duration="3000"
        android:propertyName="rotation"
        android:repeatCount="3"
        android:valueFrom="0"
        android:valueTo="360"
        android:valueType="floatType" >
    </objectAnimator>

</set>

加载我们的动画文件

Animator animator = AnimatorInflater.loadAnimator(MainActivity5.this, R.animator.property_animator);
animator.setTarget(tv_show);
animator.start();
    android:duration="3000"
    android:propertyName="rotation"
    android:repeatCount="3"
    android:valueFrom="0"
    android:valueTo="360"
    android:valueType="floatType" >
</objectAnimator>
```

加载我们的动画文件

Animator animator = AnimatorInflater.loadAnimator(MainActivity5.this, R.animator.property_animator);
animator.setTarget(tv_show);
animator.start();

外部文件的引用(butterknife)黄油刀

首先在你的Gradle Scripts 中第二个 build gradle中加入

implementation ‘com.jakewharton:butterknife:10.2.3’// 添加此依赖
annotationProcessor ‘com.jakewharton:butterknife-compiler:10.2.3’// 添加此规则

在这里插入图片描述

其次点击sync now 进行加载在这里插入图片描述
在MainActivity2中进行方便创建

在这里插入图片描述
这样我感觉比之前那种方式更方便更省事

原网站

版权声明
本文为[hqhe260]所创,转载请带上原文链接,感谢
https://blog.csdn.net/heqiang260/article/details/126041439