欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android动画使用与分析

程序员文章站 2024-03-26 11:23:35
...

Android动画分为View动画、帧动画和属性动画。

1.View动画

view动画包括平移、缩放、旋转、淡入淡出四种动画效果。
创建方式1:xml创建
文件路径res/anim/anim_test.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true"
    android:zAdjustment="normal"
    android:shareInterpolator="true"
    android:duration = "300">
    <!--平移-->
    <translate
        android:fromXDelta="0"
        android:toXDelta="100"
        android:fromYDelta="0"
        android:toYDelta="100"
        android:interpolator ="@android:anim/linear_interpolator"/>
    <!--旋转-->
    <rotate
        android:fromDegrees="0"
        android:toDegrees="90"/>
    <!--缩放-->
    <scale
        android:fromXScale="1"
        android:toXScale="0.1"
        android:fromYScale="1"
        android:toYScale="0.1"/>
     <!--淡入淡出-->
    <alpha
        android:fromAlpha="0.1"
        android:toAlpha="1.0"/>
</set>

java代码调用

 Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_test);
 button.startAnimation(animation);

创建方式2:代码创建

 AlphaAnimation alphaAnim = new AlphaAnimation(0,1);
 alphaAnim.setDuration(300);//动画持续时间
 alphaAnim.setFillAfter(true);//维持动画结束时的状态
 alphaAnim.setRepeatCount(1);//重复执行次数
 //在动画执行过程中的监听
 alphaAnim.setAnimationListener(new Animation.AnimationListener() {
     @Override
     public void onAnimationStart(Animation animation) {
         //开始动画时调用
     }

     @Override
     public void onAnimationEnd(Animation animation) {
         //结束动画时调用
     }

     @Override
     public void onAnimationRepeat(Animation animation) {
         //重复动画时调用
     }
 });
 button.startAnimation(alphaAnim);

2.帧动画

帧动画时view动画特殊的一种动画,是顺序播放预先定义好的一组图片,类似于播放电影的效果。系统通过AnimationDrawable来使用帧动画,把动画当做背景执行。首先通过xml定义播放资源,路径res/drawable/frame_anim.xml

<?xml version="1.0" encoding="utf-8"?>
<animation-list
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">

    <item android:drawable="@mipmap/image1" android:duration = "500"/>
    <item android:drawable="@mipmap/image2" android:duration = "500"/>
    <item android:drawable="@mipmap/image3" android:duration = "500"/>

</animation-list>

java代码调用

button.setBackgroundResource(R.drawable.frame_anim);
AnimationDrawable drawable = (AnimationDrawable) button.getBackground();
drawable.start();

附:View动画的特殊使用场景

A.LayoutAnimation–ViewGroup动画
作用于ViewGroup,为ViewGroup指定一个动画,效果在子元素上体现,以ListView为例,每个Item都有动画效果。
方法1:定义LayoutAnimation,路径res/anim/anim_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:delay="0.5"
    android:animationOrder="normal"
    android:animation="@anim/animation_test">
</layoutAnimation>

animation指定动画效果,在animation_test指定duration=“300”,在layoutAnimation delay="0.5"每个item每隔300*0.5=150ms执行动画,animationOrder指定动画顺序,normal从前往后依次执行,reverse从后往前依次执行,random随机执行。

在Listview的使用

<ListView
	   android:id="@+id/listView"
	    android:layout_width="match_parent"
	    android:layout_height="wrap_content"
	    android:layoutAnimation="@anim/anim_layout"
	    app:layout_constraintLeft_toLeftOf="parent"
	    app:layout_constraintTop_toBottomOf="@id/btn"/>

方法2: 在代码中为listView设置动画

  ListView listView = findViewById(R.id.listView);
  Animation animation = AnimationUtils.loadAnimation(this, R.anim.animation_test);
  LayoutAnimationController controller = new LayoutAnimationController(animation);
  controller.setDelay(0.5f);
  controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
  listView.setLayoutAnimation(controller);

效果和方式一相同。

B.Activity切换效果
用overridePendingTransition(int enterAnim,int exitAnim)指定开打和暂停的Activity的效果。只能在startActivity(intent)和finish()之后调用,否则不生效。

Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);
//Activity切换动画
overridePendingTransition(R.anim.enter_anim,R.anim.exit_anim);

3.属性动画

属性动画时API 11新特性,与View动画不同,属性动画对作用对象进一步扩展,可以对任何对象的属性做动画,甚至可以没有对象,属性动画可以实现绚丽的动画效果。属性动画有ValueAnimator、ObjectAnimator、AnimtorSet等概念。
(1)改变一个对象的translationY属性,让button向上平移自身高度

 ObjectAnimator.ofFloat(button,"translationY",-button.getWidth());

(2)改变button的背景颜色

ValueAnimator colorAnim = ObjectAnimator.ofInt(button, "backgroundColor",0xFFFF8080, 0xFF8080FF);
colorAnim.setDuration(300);
colorAnim.setEvaluator(new ArgbEvaluator());
colorAnim.setRepeatCount(ValueAnimator.INFINITE);//无限循环
colorAnim.setRepeatMode(ValueAnimator.REVERSE);//反转
colorAnim.start();

(3)采用xml方式定义,目录在res/animator/property_anim.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="together">
	<!--对应objectAnimator-->
    <objectAnimator
        android:propertyName="x"
        android:duration="300"
        android:valueTo="200"
        android:valueType="intType"/>
        
	<!--对应ValueAnimator-->
    <animator
        android:propertyName="y"
        android:duration="300"
        android:valueTo="300"
        android:valueType="intType"/>
        
	<!--对应AnimtorSet-->
    <set></set>

</set>

使用

 AnimatorSet animator = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.property_anim);
 animator.setTarget(button);
 animator.start();

时间插值器与类型估值器

时间插值器(TimeInterpolator):根据时间流逝百分比来计算出当前属性值改变的百分比,系统预置的有LinearInterpolator(线性插值器:匀速动画)、AcceleratedDecelerateInterpolator(先加速后减速)、DecelerateInterpolator(减速)。
类型估值器(TypeEvaluator):根据当前属性改变的百分比计算改变后的属性值。系统预置的有IntEvaluator、FloatEvaluator、ArgbEvaluator。

插值器与估值器是实现非匀速动画的重要手段

属性动画监听器
1.AnimationListener

public static interface AnimationListener {    
   void onAnimationStart(Animation animation);    
   void onAnimationEnd(Animation animation); 
   void onAnimationRepeat(Animation animation);
}

2.AnimatorUpdateListener
监听整个动画过程,动画是由许多帧组成的,每播放一帧都会调用该监听接口

public static interface AnimatorUpdateListener {
   void onAnimationUpdate(ValueAnimator animation);
}

对任意属性做动画

由于属性动画的特殊性,想要让动画生效,对对象object的属性abc做动画,必须满足两个条件:
(1)object必须提供setAbc方法,如果动画的时候没有传递初始值,那么还要提供getAbc方法,因为系统要取abc的初始值(若不满足,直接crash)
(2)object的setAbc对属性abc所做的改变必须通过某种方法反映出来,如UI改变等(若不满足,动画无效果不会crash)

解决方案:
1.给对象加set和get方法(有权限的情况下)
2.用一个包装类包装原始对象,间接提供get、set方法
3.采用ValueAnimator,监听动画过程、自己实现属性的改变。
方案一,一般无法取得权限(可能要修改源码),这里不讨论。
方案二,使用方便,很有效的方法

//包装类包装原始对象
private void performAnimator() {
     ViewWrapper wrapper = new ViewWrapper(button);
      ObjectAnimator.ofInt(wrapper,"width",500).setDuration(5000).start();
}

/**
 * 用一个类包装原始对象,提供get/set方法
 */
private static class ViewWrapper{

    private View target;

    public ViewWrapper(View target){
        this.target = target;
    }

    public int getWidth(){
        return target.getLayoutParams().width;// 对应xml的 layout_width
    }

    public void setWidth(int width) {
        target.getLayoutParams().width = width;
        target.requestLayout();
    }
}

方案三,采用监听的方式

private void performAnimator(final View view, final int start, final int end) {
        final ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);//进度1-100
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            private IntEvaluator evaluator = new IntEvaluator();
            //动画的每一帧都会调该方法
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //获取进度1-100
                //int curValue = (int)animation.getAnimatedValue();
                //得到进度比例
                float animatedFraction = animation.getAnimatedFraction();
                //根据进度比例用估值算法计算
                view.getLayoutParams().width = evaluator.evaluate(animatedFraction,start,end);
                view.requestLayout();

            }
        });
        valueAnimator.setDuration(5000).start();
    }

4.使用动画的注意事项

1.OOM
帧动画图片过多容易引起OOM,尽量避免使用。
2.内存泄漏
无限循环的动画,要在Activity退出时停止动画,否则Activity无法释放造成内存泄漏。
3.View动画问题
View动画影像运动,有时候出现无法隐藏的现象,需要调用view.clearAnimation()清除View动画。
4.动画尽量使用px,尽量不使用px
5.开启硬件加速,提高流畅度。
6.动画元素交互
Android3.0后动画移动后点击事件在新位置,3.0之前点击事件在新位置,但View都扔在原位置。

May you return with a young heart after years of fighting.
愿你出走半生,归来仍是少年。​​​

上一篇: 自定义checkbox样式

下一篇: