Animation 动画


珍惜作者劳动成果 转载请注明出处

根据人眼视觉残留现象,连续播放一些列的图像,形成动画效果。

Android中的动画:

  1. 游戏:利用自定义View的绘制方法,开启线程频繁的刷新界面,形成动画;
  2. Android 视图动画:针对 View 以及View的子类。
  3. Android 属性动画:针对定义的属性,大部分可以操作View

补间动画

Android根据起始状态和结束状态,进行控件的移动、旋转、缩放等显示效果的变化,形成一个动画

实现方式

  1. XML 定义动画 (Android官方推荐)
    • xml 定义在 res/anim/ 文件夹下面;
    • 这种 anim动画,需要通过 AnimationUtils 来加载
  2. 代码实现动画(可扩展性差)

  3. 补间动画,就是指定开始状态,并且指定结束状态,Android系统自动的在这两个状态之间进行填充,形成连续的动画,就被称为补间动画

  4. 代码从XML中加载 动画对象;
  5. 给需要处理的控件,设置动画就可以播放了;

补间动画特点

  1. 通过指定时间、起始状态、结束状态,通过Android系统API,来进行动态效果的呈现;
  2. 补间动画,播放完成执行,控件将会还原为原始的位置、状态;
  3. 可以根据动画的播放情况,进行动画的播放状态的监听, 通过监听器可以监测:动画的开始、循环、停止;
  4. 当动画还在播放的时候,如果再次设置控件的动画,那么当前的动画将会终止;

关于动画的平滑

  1. Android系统,播放补间动画时,根据时间,起始状态、结束状态,生成动画效果
  2. 插值器 interpolator: Android系统根据插值器,在每一个等分的时间中,来设置不同的数值

组合变化

  1. translate + scale 在 中,写入多个动画效果就可以将多种效果同时组合在一起播放。
  2. 如果希望动画是串行执行,那么后续动画的起始播放时间,需要延后!!!
  3. 补间动画的 set 最终相当于线程池,内部的每一个动画效果实际上是由一个线程执行的,所有即使一个效果无限循环,其他效果也能够执行。

补间动画的重点

  1. !!! 任何动画的操作都不会影响实际控件的状态。因为实际上补间动画只是把控件的外观进行了各种处理,相当于控件还在原来的位置,还是原来的尺寸
  2. 尝试 translate + rotate 就可以重现控件状态。
  3. 补间动画 通过 AnimationUtils.loadAnimation 进行加载的。给控件 View startAnimation(Animation) 就可以执行控件的动画了。

关于动画的接口

动画播放的时候是有状态了,例如 开始动画、动画结束
AnimationListener 包含动画三种状态的回调:

  • onAnimationStart 动画开始执行
  • onAnimationEnd 动画执行完成
  • onAnimationRepeat 动画重复执行。

几种动画效果

xml文件
res/anim/

旋转:

<!--
    android:repeatCount="infinite" 循环次数:无限循环
    android:interpolator="@android:interpolator/linear": 可以平滑旋转

-->
<rotate
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:fromDegrees="0"
    android:toDegrees="360"
    android:pivotX="50%"
    android:pivotY="50%"
    android:repeatCount="infinite"
    />

移动:

    <translate
        android:fromXDelta="0"
        android:toXDelta="200"/>

缩放:

  <!--
    缩放视图, 必须包含x, y的缩放设置
     若不设置: 默认 0 -> 0
    -->
    <scale android:fromXScale="1"
           android:toXScale="2"
            android:fromYScale="1"
           android:toYScale="2"
           android:pivotX="50%"
           android:pivotY="50%"/>

set集合

<?xml version="1.0" encoding="utf-8"?>
<!--
    动画定义的集合, 使用set来包含多个动画
    如果只有一个动画效果, 可以直接写动画的指令
    duration: 持续时间
    Delta: 增量
    startOffset: 代表当前效果在动画启动多长时间之后 执行

    补间动画实际上没有操作控件的属性
    而是把控件的显示调整了 动画播放完成后还会还原原始状态


    Android的坐标系, 左上角为圆点!!!
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <!--所有的动画效果, 都需要设置duration属性-->
    <translate
        android:duration="1000"
        android:fromYDelta="0"
        android:toYDelta="-300"
        android:fromXDelta="0"
        android:toXDelta="-300"
        />
    <!--alpha 让控件逐渐消失和显示
        startOffset 代表当前效果在动画启动多长时间之后执行 , 单位: 毫秒

    -->
    <alpha

        android:duration="1000"
        android:fromAlpha="1"
        android:toAlpha="0"/>
</set>

java 代码文件

public void btnRotateClick(View view) {
        //图片旋转
        Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_rotate);
        animation.setRepeatMode(Animation.INFINITE);

        //设置插值器 平滑旋转
        animation.setInterpolator(new LinearInterpolator());

        view.startAnimation(animation);


    }

    public void btMoveInterpolator(View view) {
        //带有插值器的移动
        Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_move);
        animation.setDuration(1000);
//        animation.setInterpolator(new OvershootInterpolator(20));
        animation.setInterpolator(new SimpleInterpolator());

        view.startAnimation(animation);
    }

    public void btnScale(View view) {
        ImageView imageView = (ImageView) findViewById(R.id.image_view);
        if (imageView != null) {
            Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_heartbeat);
            animation.setDuration(1000);
            AnimationSet animationSet = (AnimationSet) animation;
            List<Animation> animations = animationSet.getAnimations();
            Animation anim = animations.get(0);

            //设置第一次执行完成之后, 循环播放的次数
            anim.setRepeatMode(Animation.REVERSE);
            anim.setRepeatCount(Animation.INFINITE);
            imageView.startAnimation(animation);
        }
    }

动画的监听

设置动画监听: 当动画开始, 完成, 重复时, 进行回调
        animation.setAnimationListener(this);

 //Animaition监听/start/
   @Override
    public void onAnimationStart(Animation animation) {

    }

    @Override
    public void onAnimationEnd(Animation animation) {
        tvInc.setVisibility(View.INVISIBLE);

        tvZan.setText("赞" + zanCount);
    }

    @Override
    public void onAnimationRepeat(Animation animation) {

    }
    //Animaition监听///end/

逐帧动画

  1. !!! 逐帧动画是一个 drawable 可以认为是一个图片;和 shape 相似都是用 xml 写出来的。
  2. 当中,从 xml 顺序加载图片,最上面的 最先显示。
  3. 可以指定 oneshoot 属性,控制动画是否只播放一次。如果为 true,那么只播放一次,即使播放完成, 如果不进行stop的话,依然是 running的状态。代表直接start()是不会执行的,只有stop之后才可以重新start

逐帧动画的使用

  1. 准备图片资源
  2. 在drawable中编写 xml,指定每一帧的显示图片内容
  3. ImageView 或者 其他View 的background属性,指定资源,方式:@drawable/名称
  4. 代码获取ImageView ,并且获取到 background ,检查是否是 AnimationDrawable ,进行强制类型转换
  5. AnimationDrawable start(), stop(); 进行播放的控制
  6. start() 不支持继续播放,每次从头开始。

应用场景

  1. 重复的,有动画效果的提示性内容,例如:京东客户端下拉刷新的时候“快递小哥”的动画
  2. 一些小的动画,不能够使用补间动画的情况,或者显示现实世界中的人物、动画的动态效果。
  3. 主要是配合一些事件的操作,如下拉刷新、圆圈进度条的处理

代码示例

<!--
        逐帧动画, 就是在指定时间中, 依次显示每一张图片
        形成连续的动画效果
        android:oneshot="true"
        如何显示是关键
-->

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    >

    <item android:duration="200" android:drawable="@mipmap/d00"/>
         .....
    <item android:duration="200" android:drawable="@mipmap/d09"/>

</animation-list>

    public void btnPlayFrame(View view) {
        //TODO: 播放动画
        //1. 因为逐帧动画是图片, 所以要从ImageView中取出来, 才能进行控制
        ImageView imageGift = (ImageView) findViewById(R.id.image_gift);
        //获取src属性
        Drawable drawable = imageGift.getDrawable();

        //shape -> ShapeDrawable
        //animation-list -> AnimationDrawable
        if (drawable != null && drawable instanceof AnimationDrawable) {
            //2. 播放动画
            AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
            animationDrawable.start();
        }



//        imageGift.setImageDrawable();
    }


    public void btnStopFrame(View view) {
        //TODO: 停止动画
        //1. 获取图像 逐帧动画

        ImageView imageGift = (ImageView) findViewById(R.id.image_gift);
        Drawable drawable = imageGift.getDrawable();
        if (drawable != null && drawable instanceof AnimationDrawable) {
            AnimationDrawable animationDrawable = (AnimationDrawable) drawable;

            //Stop会将动画暂停, 但是下一次, start的时候, 会从头开始播放
            animationDrawable.stop();

            //Gif 如何显示: GifDrawable库  WebView

        }
    }

属性动画

  1. 属性动画定义在 res/animator/ 这个资源目录下;
  2. 属性动画:实现按时间进行控件属性的变化;
  3. 实际改变控件的属性,整个布局重新排版,而且不会还原。

objectAnimator标记

  1. 能够以动画的方式修改任意对象的属性;
  2. 能够通过 setXxxx 这种方法的自动调用,来实现对属性“xxxx” 来进行修改;
  3. 这个标记可以通过 指定属性的名称,来进行设置。

原理

这里写图片描述

执行原理

  1. Animator 通过 xml 来加载,获取需要修改的属性的名称、类型、数值;
  2. AnimatorInflator 来加载xml, 之后设置了 setTarget(Object) ,指定需要修改属性的内容的对象;
  3. 通过将属性的名称转为 JavaBean 属性方法设置命名规则:属性名首字母大写,前面添加 set,例如 left属性,那么就会生成 setLeft(数值类型) 进行反射,查找指定对象中是否包含这个方法,如果包含,就可以按照指定的时间(duration) 进行 valueFrom 到 valueTo 这两值之间的进行动态的设置。

实现步骤

  1. 准备属性动画的XML动画资源;
  2. 准备需要播放动画的对象;
  3. 加载属性动画的 XML
  4. 设置动画要修改的对象
  5. 修改的属性名称,一定是 Java类文件中的 public void setXxxxx(… xxx) 的方法的 xxxx 这个属性,首字母小写

属性动画的Target的设置

  1. 比较常见的是 View
  2. 修改的属性都是 color, dimension, int, float
  3. 属性动画还可以指定非 View的对象。官方使用采用的自定义的Object,然后再Object setXxxx() 内部来实现更强大功能。
    这里写图片描述

动画执行序列 < set>

set 标签可以 通过 ordering属性进行设置,内部的动画是否在一起执行
sequentially 串行执行,一个执行完,在执行另外的一个,不要有无限重复的,因为后边的没法执行了
together 并行一起执行

V4包动画支持

ViewCompat 支持 设置View的状态,例如 ViewCompat.setScaleX(View, float) 就是缩放控件水平方向的尺寸;
ViewPropertyAnimatorCompat 支持 实现低版本手机的属性动画功能,
ViewCompat.animate(View) 为View创建一个属性动画对象

动画与事件的配合

ScrollView 的 onTouch 中的 MOVE 事件可以和控件的隐藏显示配合
ListView OnScrollListener 可以检测ListView的滚动,滚动的过程中可以实现图片,标题的缩放

代码实例

res/animator/

 <!--
        设置对象属性修改器, 可以在指定的时间之内,
         将指定的属性, 从一个数值变换到另一个数值
     -->

    <!-- setTranslationX(float x)-->

    <objectAnimator
        android:duration="1000"
        android:propertyName="translationX"
        android:valueType="floatType"
        android:valueFrom="0dp"
        android:interpolator="@android:interpolator/overshoot"
        android:valueTo="200dp"/>

    <objectAnimator
        android:interpolator="@android:interpolator/linear"
        android:duration="1000"
        android:propertyName="rotation"
        android:valueType="floatType"
        android:valueFrom="0"
        android:valueTo="360"/>

java


    public void btnPropertyMove(View view) {
        //属性动画的加载
        //1. 加载器 加载xml文件
        Animator animator = AnimatorInflater.loadAnimator(this,
                R.animator.animator_move);
        //2. 将需要修改的对象传递给属性动画
        animator.setTarget(mTextView);
        //3. 动画的播放

        animator.start();
    }

    public void btnPropertyColor(View view) {
        Animator animator = AnimatorInflater.loadAnimator(this, R.animator.animator_color);
        animator.setTarget(mTextView);
        animator.start();
    }

    public void btnPropertyTextSize(View view) {
        Animator animator = AnimatorInflater.loadAnimator(this, R.animator.animator_textsize);
        animator.setTarget(mTextView);
        animator.start();


    }

    public void btnPropertyCustom(View view) {
        //自定义对象的属性修改

        //1. 自定义类对象: 确认属性名
        TextShower shower = new TextShower(mTextView);
        //2. 加载xml或者写代码
        Animator animator = AnimatorInflater.loadAnimator(this, R.animator.anmiator_text_show);
        //3. 设置目标
        animator.setTarget(shower);
        animator.start();



    }

    public void btnPropertyCode(View view) {
        //代码形式的属性动画
        //所有的属性的数值,如果是位置那么以像素为单位
//     ObjectAnimator.ofFloat(mTextView, "translationX", 0, 200).setDuration(2000).start();
        //利用set 可以实现多个属性同时修改

        AnimatorSet set = new AnimatorSet();
        ObjectAnimator animator1 = ObjectAnimator.ofFloat(mTextView, "translationX", 0, 400).setDuration(2000);
        ObjectAnimator animator2 = ObjectAnimator.ofFloat(mTextView, "rotation", 0, 360).setDuration(200);
        set.playTogether(animator1, animator2);
        set.start();

    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值