精华内容
下载资源
问答
  • 使用css把一张图片变成一部小动画(steps) 申明: 我只是知识的搬运工。 只要会做雪碧图就可以把一张图做成一个有意思的小动画,不是需要使用PS,不需要使用AE。 样式使用及说明 制作一张这样的png图片。 样式...

    一张雪碧图做一个小动画,不是需要制作gif,不需要制作视屏。(温馨提醒,请勿盗图哦~)

    样式使用及说明

    在这里插入图片描述

    • 制作一张这样的png图片。

    • 样式如下

    1. data-standard {
      width: 124px;
      height: 131px;
      background: url("…/images/animation/data_standard.png") no-repeat;
      animation: standard steps(7, end) 2s infinite;
      -ms-animation: standard steps(7, end) 2s infinite;
      -webkit-animation: standard steps(7, end) 2s infinite;
      -moz-animation: standard steps(7, end) 2s infinite;
      }

    2. @keyframes standard {
      100% {
      background-position: 0 -917px;// 以最后一针的图片的最后一个像素为终点
      }
      }

    3. @-ms-keyframes standard {
      100% {
      background-position: 0 -917px;
      }

    效果显示

    在这里插入图片描述

    知识整理

    • animation中的steps()逐帧动画
    1. 第一个参数 number 为指定的间隔数,即把动画分为几步展示,(必须是正整数)
    2. 第二个参数默认是end,设置最后一步的状态,即第一帧是第一步动画的开始
    3. 第二个参数如果设置为start时, 即第一帧是第一步动画的结束
    展开全文
  • 逐帧动画的工作原理很简单,其实就是将一个完整的动画拆分成一张张单独的图片,然后再将它们连贯起来进行播放,类似于动画片的工作原理。补间动画则是可以对View进行一系列的动画操作,包括淡入淡出、缩放、平移、...

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/43536355


    在手机上去实现一些动画效果算是件比较炫酷的事情,因此Android系统在一开始的时候就给我们提供了两种实现动画效果的方式,逐帧动画(frame-by-frame animation)和补间动画(tweened animation)。逐帧动画的工作原理很简单,其实就是将一个完整的动画拆分成一张张单独的图片,然后再将它们连贯起来进行播放,类似于动画片的工作原理。补间动画则是可以对View进行一系列的动画操作,包括淡入淡出、缩放、平移、旋转四种。


    然而自Android 3.0版本开始,系统给我们提供了一种全新的动画模式,属性动画(property animation),它的功能非常强大,弥补了之前补间动画的一些缺陷,几乎是可以完全替代掉补间动画了。对于逐帧动画和补间动画的用法,我不想再多讲,它们的技术已经比较老了,而且网上资料也非常多,那么今天我们这篇文章的主题就是对Android属性动画进行一次完全解析。


    为什么要引入属性动画?


    Android之前的补间动画机制其实还算是比较健全的,在android.view.animation包下面有好多的类可以供我们操作,来完成一系列的动画效果,比如说对View进行移动、缩放、旋转和淡入淡出,并且我们还可以借助AnimationSet来将这些动画效果组合起来使用,除此之外还可以通过配置Interpolator来控制动画的播放速度等等等等。那么这里大家可能要产生疑问了,既然之前的动画机制已经这么健全了,为什么还要引入属性动画呢?


    其实上面所谓的健全都是相对的,如果你的需求中只需要对View进行移动、缩放、旋转和淡入淡出操作,那么补间动画确实已经足够健全了。但是很显然,这些功能是不足以覆盖所有的场景的,一旦我们的需求超出了移动、缩放、旋转和淡入淡出这四种对View的操作,那么补间动画就不能再帮我们忙了,也就是说它在功能和可扩展方面都有相当大的局限性,那么下面我们就来看看补间动画所不能胜任的场景。


    注意上面我在介绍补间动画的时候都有使用“对View进行操作”这样的描述,没错,补间动画是只能够作用在View上的。也就是说,我们可以对一个Button、TextView、甚至是LinearLayout、或者其它任何继承自View的组件进行动画操作,但是如果我们想要对一个非View的对象进行动画操作,抱歉,补间动画就帮不上忙了。可能有的朋友会感到不能理解,我怎么会需要对一个非View的对象进行动画操作呢?这里我举一个简单的例子,比如说我们有一个自定义的View,在这个View当中有一个Point对象用于管理坐标,然后在onDraw()方法当中就是根据这个Point对象的坐标值来进行绘制的。也就是说,如果我们可以对Point对象进行动画操作,那么整个自定义View的动画效果就有了。显然,补间动画是不具备这个功能的,这是它的第一个缺陷。


    然后补间动画还有一个缺陷,就是它只能够实现移动、缩放、旋转和淡入淡出这四种动画操作,那如果我们希望可以对View的背景色进行动态地改变呢?很遗憾,我们只能靠自己去实现了。说白了,之前的补间动画机制就是使用硬编码的方式来完成的,功能限定死就是这些,基本上没有任何扩展性可言。


    最后,补间动画还有一个致命的缺陷,就是它只是改变了View的显示效果而已,而不会真正去改变View的属性。什么意思呢?比如说,现在屏幕的左上角有一个按钮,然后我们通过补间动画将它移动到了屏幕的右下角,现在你可以去尝试点击一下这个按钮,点击事件是绝对不会触发的,因为实际上这个按钮还是停留在屏幕的左上角,只不过补间动画将这个按钮绘制到了屏幕的右下角而已。


    也正是因为这些原因,Android开发团队决定在3.0版本当中引入属性动画这个功能,那么属性动画是不是就把上述的问题全部解决掉了?下面我们就来一起看一看。


    新引入的属性动画机制已经不再是针对于View来设计的了,也不限定于只能实现移动、缩放、旋转和淡入淡出这几种动画操作,同时也不再只是一种视觉上的动画效果了。它实际上是一种不断地对值进行操作的机制,并将值赋值到指定对象的指定属性上,可以是任意对象的任意属性。所以我们仍然可以将一个View进行移动或者缩放,但同时也可以对自定义View中的Point对象进行动画操作了。我们只需要告诉系统动画的运行时长,需要执行哪种类型的动画,以及动画的初始值和结束值,剩下的工作就可以全部交给系统去完成了。


    既然属性动画的实现机制是通过对目标对象进行赋值并修改其属性来实现的,那么之前所说的按钮显示的问题也就不复存在了,如果我们通过属性动画来移动一个按钮,那么这个按钮就是真正的移动了,而不再是仅仅在另外一个位置绘制了而已。


    好了,介绍了这么多,相信大家已经对属性动画有了一个最基本的认识了,下面我们就来开始学习一下属性动画的用法。


    ValueAnimator


    ValueAnimator是整个属性动画机制当中最核心的一个类,前面我们已经提到了,属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等,确实是一个非常重要的类。


    但是ValueAnimator的用法却一点都不复杂,我们先从最简单的功能看起吧,比如说想要将一个值从0平滑过渡到1,时长300毫秒,就可以这样写:

    ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
    anim.setDuration(300);
    anim.start();

    怎么样?很简单吧,调用ValueAnimator的ofFloat()方法就可以构建出一个ValueAnimator的实例,ofFloat()方法当中允许传入多个float类型的参数,这里传入0和1就表示将值从0平滑过渡到1,然后调用ValueAnimator的setDuration()方法来设置动画运行的时长,最后调用start()方法启动动画。


    用法就是这么简单,现在如果你运行一下上面的代码,动画就会执行了。可是这只是一个将值从0过渡到1的动画,又看不到任何界面效果,我们怎样才能知道这个动画是不是已经真正运行了呢?这就需要借助监听器来实现了,如下所示:

    ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
    anim.setDuration(300);
    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            float currentValue = (float) animation.getAnimatedValue();
            Log.d("TAG", "cuurent value is " + currentValue);
        }
    });
    anim.start();

    可以看到,这里我们通过addUpdateListener()方法来添加一个动画的监听器,在动画执行的过程中会不断地进行回调,我们只需要在回调方法当中将当前的值取出并打印出来,就可以知道动画有没有真正运行了。运行上述代码,控制台打印如下所示:




    从打印日志的值我们就可以看出,ValueAnimator确实已经在正常工作了,值在300毫秒的时间内从0平滑过渡到了1,而这个计算工作就是由ValueAnimator帮助我们完成的。另外ofFloat()方法当中是可以传入任意多个参数的,因此我们还可以构建出更加复杂的动画逻辑,比如说将一个值在5秒内从0过渡到5,再过渡到3,再过渡到10,就可以这样写:

    ValueAnimator anim = ValueAnimator.ofFloat(0f, 5f, 3f, 10f);
    anim.setDuration(5000);
    anim.start();
    当然也许你并不需要小数位数的动画过渡,可能你只是希望将一个整数值从0平滑地过渡到100,那么也很简单,只需要调用ValueAnimator的ofInt()方法就可以了,如下所示:
    ValueAnimator anim = ValueAnimator.ofInt(0, 100);

    ValueAnimator当中最常用的应该就是ofFloat()和ofInt()这两个方法了,另外还有一个ofObject()方法,我会在下篇文章进行讲解。


    那么除此之外,我们还可以调用setStartDelay()方法来设置动画延迟播放的时间,调用setRepeatCount()和setRepeatMode()方法来设置动画循环播放的次数以及循环播放的模式,循环模式包括RESTART和REVERSE两种,分别表示重新播放和倒序播放的意思。这些方法都很简单,我就不再进行详细讲解了。


    ObjectAnimator


    相比于ValueAnimator,ObjectAnimator可能才是我们最常接触到的类,因为ValueAnimator只不过是对值进行了一个平滑的动画过渡,但我们实际使用到这种功能的场景好像并不多。而ObjectAnimator则就不同了,它是可以直接对任意对象的任意属性进行动画操作的,比如说View的alpha属性。


    不过虽说ObjectAnimator会更加常用一些,但是它其实是继承自ValueAnimator的,底层的动画实现机制也是基于ValueAnimator来完成的,因此ValueAnimator仍然是整个属性动画当中最核心的一个类。那么既然是继承关系,说明ValueAnimator中可以使用的方法在ObjectAnimator中也是可以正常使用的,它们的用法也非常类似,这里如果我们想要将一个TextView在5秒中内从常规变换成全透明,再从全透明变换成常规,就可以这样写:

    ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
    animator.setDuration(5000);
    animator.start();

    可以看到,我们还是调用了ofFloat()方法来去创建一个ObjectAnimator的实例,只不过ofFloat()方法当中接收的参数有点变化了。这里第一个参数要求传入一个object对象,我们想要对哪个对象进行动画操作就传入什么,这里我传入了一个textview。第二个参数是想要对该对象的哪个属性进行动画操作,由于我们想要改变TextView的不透明度,因此这里传入"alpha"。后面的参数就是不固定长度了,想要完成什么样的动画就传入什么值,这里传入的值就表示将TextView从常规变换成全透明,再从全透明变换成常规。之后调用setDuration()方法来设置动画的时长,然后调用start()方法启动动画,效果如下图所示:




    学会了这一个用法之后,其它的用法我们就可以举一反三了,那比如说我们想要将TextView进行一次360度的旋转,就可以这样写:

    ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);
    animator.setDuration(5000);
    animator.start();

    可以看到,这里我们将第二个参数改成了"rotation",然后将动画的初始值和结束值分别设置成0和360,现在运行一下代码,效果如下图所示:




    那么如果想要将TextView先向左移出屏幕,然后再移动回来,就可以这样写:

    float curTranslationX = textview.getTranslationX();
    ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "translationX", curTranslationX, -500f, curTranslationX);
    animator.setDuration(5000);
    animator.start();

    这里我们先是调用了TextView的getTranslationX()方法来获取到当前TextView的translationX的位置,然后ofFloat()方法的第二个参数传入"translationX",紧接着后面三个参数用于告诉系统TextView应该怎么移动,现在运行一下代码,效果如下图所示:




    然后我们还可以TextView进行缩放操作,比如说将TextView在垂直方向上放大3倍再还原,就可以这样写:

    ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "scaleY", 1f, 3f, 1f);
    animator.setDuration(5000);
    animator.start();

    这里将ofFloat()方法的第二个参数改成了"scaleY",表示在垂直方向上进行缩放,现在重新运行一下程序,效果如下图所示:




    到目前为止,ObjectAnimator的用法还算是相当简单吧,但是我相信肯定会有不少朋友现在心里都有同样一个疑问,就是ofFloat()方法的第二个参数到底可以传哪些值呢?目前我们使用过了alpha、rotation、translationX和scaleY这几个值,分别可以完成淡入淡出、旋转、水平移动、垂直缩放这几种动画,那么还有哪些值是可以使用的呢?其实这个问题的答案非常玄乎,就是我们可以传入任意的值到ofFloat()方法的第二个参数当中。任意的值?相信这很出乎大家的意料吧,但事实就是如此。因为ObjectAnimator在设计的时候就没有针对于View来进行设计,而是针对于任意对象的,它所负责的工作就是不断地向某个对象中的某个属性进行赋值,然后对象根据属性值的改变再来决定如何展现出来。


    那么比如说我们调用下面这样一段代码:

    ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f);

    其实这段代码的意思就是ObjectAnimator会帮我们不断地改变textview对象中alpha属性的值,从1f变化到0f。然后textview对象需要根据alpha属性值的改变来不断刷新界面的显示,从而让用户可以看出淡入淡出的动画效果。


    那么textview对象中是不是有alpha属性这个值呢?没有,不仅textview没有这个属性,连它所有的父类也是没有这个属性的!这就奇怪了,textview当中并没有alpha这个属性,ObjectAnimator是如何进行操作的呢?其实ObjectAnimator内部的工作机制并不是直接对我们传入的属性名进行操作的,而是会去寻找这个属性名对应的get和set方法,因此alpha属性所对应的get和set方法应该就是:

    public void setAlpha(float value);
    public float getAlpha();

    那么textview对象中是否有这两个方法呢?确实有,并且这两个方法是由View对象提供的,也就是说不仅TextView可以使用这个属性来进行淡入淡出动画操作,任何继承自View的对象都可以的。


    既然alpha是这个样子,相信大家一定已经明白了,前面我们所用的所有属性都是这个工作原理,那么View当中一定也存在着setRotation()、getRotation()、setTranslationX()、getTranslationX()、setScaleY()、getScaleY()这些方法,不信的话你可以到View当中去找一下。


    组合动画


    独立的动画能够实现的视觉效果毕竟是相当有限的,因此将多个动画组合到一起播放就显得尤为重要。幸运的是,Android团队在设计属性动画的时候也充分考虑到了组合动画的功能,因此提供了一套非常丰富的API来让我们将多个动画组合到一起。


    实现组合动画功能主要需要借助AnimatorSet这个类,这个类提供了一个play()方法,如果我们向这个方法中传入一个Animator对象(ValueAnimator或ObjectAnimator)将会返回一个AnimatorSet.Builder的实例,AnimatorSet.Builder中包括以下四个方法:

    • after(Animator anim)   将现有动画插入到传入的动画之后执行
    • after(long delay)   将现有动画延迟指定毫秒后执行
    • before(Animator anim)   将现有动画插入到传入的动画之前执行
    • with(Animator anim)   将现有动画和传入的动画同时执行

    好的,有了这四个方法,我们就可以完成组合动画的逻辑了,那么比如说我们想要让TextView先从屏幕外移动进屏幕,然后开始旋转360度,旋转的同时进行淡入淡出操作,就可以这样写:

    ObjectAnimator moveIn = ObjectAnimator.ofFloat(textview, "translationX", -500f, 0f);
    ObjectAnimator rotate = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);
    ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
    AnimatorSet animSet = new AnimatorSet();
    animSet.play(rotate).with(fadeInOut).after(moveIn);
    animSet.setDuration(5000);
    animSet.start();

    可以看到,这里我们先是把三个动画的对象全部创建出来,然后new出一个AnimatorSet对象之后将这三个动画对象进行播放排序,让旋转和淡入淡出动画同时进行,并把它们插入到了平移动画的后面,最后是设置动画时长以及启动动画。运行一下上述代码,效果如下图所示:




    Animator监听器


    在很多时候,我们希望可以监听到动画的各种事件,比如动画何时开始,何时结束,然后在开始或者结束的时候去执行一些逻辑处理。这个功能是完全可以实现的,Animator类当中提供了一个addListener()方法,这个方法接收一个AnimatorListener,我们只需要去实现这个AnimatorListener就可以监听动画的各种事件了。


    大家已经知道,ObjectAnimator是继承自ValueAnimator的,而ValueAnimator又是继承自Animator的,因此不管是ValueAnimator还是ObjectAnimator都是可以使用addListener()这个方法的。另外AnimatorSet也是继承自Animator的,因此addListener()这个方法算是个通用的方法。


    添加一个监听器的代码如下所示:

    anim.addListener(new AnimatorListener() {
    	@Override
    	public void onAnimationStart(Animator animation) {
    	}
    
    	@Override
    	public void onAnimationRepeat(Animator animation) {
    	}
    
    	@Override
    	public void onAnimationEnd(Animator animation) {
    	}
    
    	@Override
    	public void onAnimationCancel(Animator animation) {
    	}
    });

    可以看到,我们需要实现接口中的四个方法,onAnimationStart()方法会在动画开始的时候调用,onAnimationRepeat()方法会在动画重复执行的时候调用,onAnimationEnd()方法会在动画结束的时候调用,onAnimationCancel()方法会在动画被取消的时候调用。


    但是也许很多时候我们并不想要监听那么多个事件,可能我只想要监听动画结束这一个事件,那么每次都要将四个接口全部实现一遍就显得非常繁琐。没关系,为此Android提供了一个适配器类,叫作AnimatorListenerAdapter,使用这个类就可以解决掉实现接口繁琐的问题了,如下所示:

    anim.addListener(new AnimatorListenerAdapter() {
    });
    这里我们向addListener()方法中传入这个适配器对象,由于AnimatorListenerAdapter中已经将每个接口都实现好了,所以这里不用实现任何一个方法也不会报错。那么如果我想监听动画结束这个事件,就只需要单独重写这一个方法就可以了,如下所示:
    anim.addListener(new AnimatorListenerAdapter() {
    	@Override
    	public void onAnimationEnd(Animator animation) {
    	}
    });


    使用XML编写动画


    我们可以使用代码来编写所有的动画功能,这也是最常用的一种做法。不过,过去的补间动画除了使用代码编写之外也是可以使用XML编写的,因此属性动画也提供了这一功能,即通过XML来完成和代码一样的属性动画功能。


    通过XML来编写动画可能会比通过代码来编写动画要慢一些,但是在重用方面将会变得非常轻松,比如某个将通用的动画编写到XML里面,我们就可以在各个界面当中轻松去重用它。


    如果想要使用XML来编写动画,首先要在res目录下面新建一个animator文件夹,所有属性动画的XML文件都应该存放在这个文件夹当中。然后在XML文件中我们一共可以使用如下三种标签:

    • <animator>  对应代码中的ValueAnimator
    • <objectAnimator>  对应代码中的ObjectAnimator
    • <set>  对应代码中的AnimatorSet

    那么比如说我们想要实现一个从0到100平滑过渡的动画,在XML当中就可以这样写:

    <animator xmlns:android="http://schemas.android.com/apk/res/android"
        android:valueFrom="0"
        android:valueTo="100"
        android:valueType="intType"/>
    而如果我们想将一个视图的alpha属性从1变成0,就可以这样写:
    <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
        android:valueFrom="1"
        android:valueTo="0"
        android:valueType="floatType"
        android:propertyName="alpha"/>
    其实XML编写动画在可读性方面还是挺高的,上面的内容相信不用我做解释大家也都看得懂吧。


    另外,我们也可以使用XML来完成复杂的组合动画操作,比如将一个视图先从屏幕外移动进屏幕,然后开始旋转360度,旋转的同时进行淡入淡出操作,就可以这样写:

    <set xmlns:android="http://schemas.android.com/apk/res/android"
        android:ordering="sequentially" >
    
        <objectAnimator
            android:duration="2000"
            android:propertyName="translationX"
            android:valueFrom="-500"
            android:valueTo="0"
            android:valueType="floatType" >
        </objectAnimator>
    
        <set android:ordering="together" >
            <objectAnimator
                android:duration="3000"
                android:propertyName="rotation"
                android:valueFrom="0"
                android:valueTo="360"
                android:valueType="floatType" >
            </objectAnimator>
    
            <set android:ordering="sequentially" >
                <objectAnimator
                    android:duration="1500"
                    android:propertyName="alpha"
                    android:valueFrom="1"
                    android:valueTo="0"
                    android:valueType="floatType" >
                </objectAnimator>
                <objectAnimator
                    android:duration="1500"
                    android:propertyName="alpha"
                    android:valueFrom="0"
                    android:valueTo="1"
                    android:valueType="floatType" >
                </objectAnimator>
            </set>
        </set>
    
    </set>
    这段XML实现的效果和我们刚才通过代码来实现的组合动画的效果是一模一样的,每个参数的含义都非常清楚,相信大家都是一看就懂,我就不再一一解释了。


    最后XML文件是编写好了,那么我们如何在代码中把文件加载进来并将动画启动呢?只需调用如下代码即可:

    Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_file);
    animator.setTarget(view);
    animator.start();
    调用AnimatorInflater的loadAnimator来将XML动画文件加载进来,然后再调用setTarget()方法将这个动画设置到某一个对象上面,最后再调用start()方法启动动画就可以了,就是这么简单。


    好的,通过本篇文章的学习,我相信大家已经对属性动画的基本用法已经有了一个相当不错的认识,并把最常用的一些功能都掌握好了,那么本篇文章的内容就到这里,下篇文章当中会继续介绍属性动画,讲解ValueAnimator和ObjectAnimator的高级用法,感兴趣的朋友请继续阅读 Android属性动画完全解析(中),ValueAnimator和ObjectAnimator的高级用法 。


    关注我的技术公众号,每天都有优质技术文章推送。关注我的娱乐公众号,工作、学习累了的时候放松一下自己。

    微信扫一扫下方二维码即可关注:

            

    展开全文
  • 动画

    2019-04-28 09:49:27
    Android 动画总结 Android 动画分类 总的来说,Android动画可以分为两类,最初的传统...帧动画是最容易实现的一种动画,这种动画更多的依赖于完善的UI资源,他的原理就是将一张张单独的图片连贯的进行播放, 从而在...

    Android 动画总结

    Android 动画分类

    总的来说,Android动画可以分为两类,最初的传统动画和Android3.0 之后出现的属性动画;
    传统动画又包括 帧动画(Frame Animation)和补间动画(Tweened Animation)。

    传统动画
    帧动画
    帧动画是最容易实现的一种动画,这种动画更多的依赖于完善的UI资源,他的原理就是将一张张单独的图片连贯的进行播放,
    从而在视觉上产生一种动画的效果;有点类似于某些软件制作gif动画的方式。

    frame.gif
    如上图中的京东加载动画,代码要做的事情就是把一幅幅的图片按顺序显示,造成动画的视觉效果。

    京东动画实现

    <?xml version="1.0" encoding="utf-8"?> protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_frame_animation); ImageView animationImg1 = (ImageView) findViewById(R.id.animation1); animationImg1.setImageResource(R.drawable.frame_anim1); AnimationDrawable animationDrawable1 = (AnimationDrawable) animationImg1.getDrawable(); animationDrawable1.start(); } 可以说,图片资源决定了这种方式可以实现怎样的动画

    在有些代码中,我们还会看到android:oneshot=“false” ,这个oneshot 的含义就是动画执行一次(true)还是循环执行多次。

    这里其他几个动画实现方式都是一样,无非就是图片资源的差异。

    补间动画
    补间动画又可以分为四种形式,分别是 alpha(淡入淡出),translate(位移),scale(缩放大小),rotate(旋转)。
    补间动画的实现,一般会采用xml 文件的形式;代码会更容易书写和阅读,同时也更容易复用。

    XML 实现
    首先,在res/anim/ 文件夹下定义如下的动画实现方式

    alpha_anim.xml 动画实现

    <?xml version="1.0" encoding="utf-8"?>


    scale.xml 动画实现

    <?xml version="1.0" encoding="utf-8"?>


    然后,在Activity中

    Animation animation = AnimationUtils.loadAnimation(mContext, R.anim.alpha_anim);
    img = (ImageView) findViewById(R.id.img);
    img.startAnimation(animation);
    这样就可以实现ImageView alpha 透明变化的动画效果。

    也可以使用set 标签将多个动画组合(代码源自Android SDK API)

    <?xml version="1.0" encoding="utf-8"?>

    <set xmlns:android=“http://schemas.android.com/apk/res/android
    android:interpolator="@[package:]anim/interpolator_resource"
    android:shareInterpolator=[“true” | “false”] >








    可以看到组合动画是可以嵌套使用的。

    各个动画属性的含义结合动画自身的特点应该很好理解,就不一一阐述了;这里主要说一下interpolator 和 pivot。

    Interpolator 主要作用是可以控制动画的变化速率 ,就是动画进行的快慢节奏。

    Android 系统已经为我们提供了一些Interpolator ,比如 accelerate_decelerate_interpolator,accelerate_interpolator等。更多的interpolator 及其含义可以在Android SDK 中查看。同时这个Interpolator也是可以自定义的,这个后面还会提到。

    pivot 决定了当前动画执行的参考位置

    pivot 这个属性主要是在translate 和 scale 动画中,这两种动画都牵扯到view 的“物理位置“发生变化,所以需要一个参考点。而pivotX和pivotY就共同决定了这个点;它的值可以是float或者是百分比数值。

    我们以pivotX为例,

    pivotX取值 含义
    10 距离动画所在view自身左边缘10像素
    10% 距离动画所在view自身左边缘 的距离是整个view宽度的10%
    10%p 距离动画所在view父控件左边缘的距离是整个view宽度的10%
    pivotY 也是相同的原理,只不过变成的纵向的位置。如果还是不明白可以参考源码,在Tweened Animation中结合seekbar的滑动观察rotate的变化理解。

    rotate1.gif
    Java 直接实现
    有时候,动画的属性值可能需要动态的调整,这个时候使用xml 就不合适了,需要使用java代码实现

    private void RotateAnimation() {
    animation = new RotateAnimation(-deValue, deValue, Animation.RELATIVE_TO_SELF,
    pxValue, Animation.RELATIVE_TO_SELF, pyValue);
    animation.setDuration(timeValue);

        if (keep.isChecked()) {
            animation.setFillAfter(true);
        } else {
            animation.setFillAfter(false);
        }
        if (loop.isChecked()) {
            animation.setRepeatCount(-1);
        } else {
            animation.setRepeatCount(0);
        }
    
        if (reverse.isChecked()) {
            animation.setRepeatMode(Animation.REVERSE);
        } else {
            animation.setRepeatMode(Animation.RESTART);
        }
        img.startAnimation(animation);
    }
    

    这里animation.setFillAfter决定了动画在播放结束时是否保持最终的状态;animation.setRepeatCount和animation.setRepeatMode 决定了动画的重复次数及重复方式,具体细节可查看源码理解。

    好了,传统动画的内容就说到这里了。

    属性动画
    属性动画,顾名思义它是对于对象属性的动画。因此,所有补间动画的内容,都可以通过属性动画实现。

    属性动画入门
    首先我们来看看如何用属性动画实现上面补间动画的效果

    private void RotateAnimation() {
        ObjectAnimator anim = ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f);
        anim.setDuration(1000);
        anim.start();
    }
    
    private void AlpahAnimation() {
        ObjectAnimator anim = ObjectAnimator.ofFloat(myView, "alpha", 1.0f, 0.8f, 0.6f, 0.4f, 0.2f, 0.0f);
        anim.setRepeatCount(-1);
        anim.setRepeatMode(ObjectAnimator.REVERSE);
        anim.setDuration(2000);
        anim.start();
    }
    

    这两个方法用属性动画的方式分别实现了旋转动画和淡入淡出动画,其中setDuration、setRepeatMode及setRepeatCount和补间动画中的概念是一样的。

    可以看到,属性动画貌似强大了许多,实现很方便,同时动画可变化的值也有了更多的选择,动画所能呈现的细节也更多。

    当然属性动画也是可以组合实现的

                ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(myView, "alpha", 1.0f, 0.5f, 0.8f, 1.0f);
                ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(myView, "scaleX", 0.0f, 1.0f);
                ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(myView, "scaleY", 0.0f, 2.0f);
                ObjectAnimator rotateAnim = ObjectAnimator.ofFloat(myView, "rotation", 0, 360);
                ObjectAnimator transXAnim = ObjectAnimator.ofFloat(myView, "translationX", 100, 400);
                ObjectAnimator transYAnim = ObjectAnimator.ofFloat(myView, "tranlsationY", 100, 750);
                AnimatorSet set = new AnimatorSet();
                set.playTogether(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);
    

    // set.playSequentially(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);
    set.setDuration(3000);
    set.start();
    可以看到这些动画可以同时播放,或者是按序播放。

    属性动画核心原理
    在上面实现属性动画的时候,我们反复的使用到了ObjectAnimator 这个类,这个类继承自ValueAnimator,使用这个类可以对任意对象的任意属性进行动画操作。而ValueAnimator是整个属性动画机制当中最核心的一个类;这点从下面的图片也可以看出。

    valueanimator.png
    属性动画核心原理,此图来自于Android SDK API 文档。

    属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等。

    从上图我们可以了解到,通过duration、startPropertyValue和endPropertyValue 等值,我们就可以定义动画运行时长,初始值和结束值。然后通过start方法开始动画。
    那么ValueAnimator 到底是怎样实现从初始值平滑过渡到结束值的呢?这个就是由TypeEvaluator 和TimeInterpolator 共同决定的。

    具体来说,TypeEvaluator 决定了动画如何从初始值过渡到结束值。
    TimeInterpolator 决定了动画从初始值过渡到结束值的节奏。

    说的通俗一点,你每天早晨出门去公司上班,TypeEvaluator决定了你是坐公交、坐地铁还是骑车;而当你决定骑车后,TimeInterpolator决定了你一路上骑行的方式,你可以匀速的一路骑到公司,你也可以前半程骑得飞快,后半程骑得慢悠悠。

    如果,还是不理解,那么就看下面的代码吧。首先看一下下面的这两个gif动画,一个小球在屏幕上以 y=sin(x) 的数学函数轨迹运行,同时小球的颜色和半径也发生着变化,可以发现,两幅图动画变化的节奏也是不一样的。

    anim1.gif
    anim2.gif
    如果不考虑属性动画,这样的一个动画纯粹的使用Canvas+Handler的方式绘制也是有可能实现的。但是会复杂很多,而且加上各种线程,会带来很多意想不到的问题。

    这里就通过自定义属性动画的方式看看这个动画是如何实现的。

    属性动画自定义实现
    这个动画最关键的三点就是 运动轨迹、小球半径及颜色的变化;我们就从这三个方面展开。最后我们在结合Interpolator说一下TimeInterpolator的意义。

    用TypeEvaluator 确定运动轨迹
    前面说了,TypeEvaluator决定了动画如何从初始值过渡到结束值。这个TypeEvaluator是个接口,我们可以实现这个接口。

    public class PointSinEvaluator implements TypeEvaluator {

    @Override
    public Object evaluate(float fraction, Object startValue, Object endValue) {
        Point startPoint = (Point) startValue;
        Point endPoint = (Point) endValue;
        float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());
    
        float y = (float) (Math.sin(x * Math.PI / 180) * 100) + endPoint.getY() / 2;
        Point point = new Point(x, y);
        return point;
    }
    

    }
    PointSinEvaluator 继承了TypeEvaluator类,并实现了他唯一的方法evaluate;这个方法有三个参数,第一个参数fraction 代表当前动画完成的百分比,这个值是如何变化的后面还会提到;第二个和第三个参数代表动画的初始值和结束值。这里我们的逻辑很简单,x的值随着fraction 不断变化,并最终达到结束值;y的值就是当前x值所对应的sin(x) 值,然后用x 和 y 产生一个新的点(Point对象)返回。

    这样我们就可以使用这个PointSinEvaluator 生成属性动画的实例了。

        Point startP = new Point(RADIUS, RADIUS);//初始值(起点)
        Point endP = new Point(getWidth() - RADIUS, getHeight() - RADIUS);//结束值(终点)
        final ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointSinEvaluator(), startP, endP);
        valueAnimator.setRepeatCount(-1);
        valueAnimator.setRepeatMode(ValueAnimator.REVERSE);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                currentPoint = (Point) animation.getAnimatedValue();
                postInvalidate();
            }
        });
    

    这样我们就完成了动画轨迹的定义,现在只要调用valueAnimator.start() 方法,就会绘制出一个正弦曲线的轨迹。

    颜色及半径动画实现
    之前我们说过,使用ObjectAnimator 可以对任意对象的任意属性进行动画操作,这句话是不太严谨的,这个任意属性还需要有get 和 set 方法。

    public class PointAnimView extends View {

    /**
     * 实现关于color 的属性动画
     */
    private int color;
    private float radius = RADIUS;
    
    .....
    

    }
    这里在我们的自定义view中,定义了两个属性color 和 radius,并实现了他们各自的get set 方法,这样我们就可以使用属性动画的特点实现小球颜色变化的动画和半径变化的动画。

        ObjectAnimator animColor = ObjectAnimator.ofObject(this, "color", new ArgbEvaluator(), Color.GREEN,
                Color.YELLOW, Color.BLUE, Color.WHITE, Color.RED);
        animColor.setRepeatCount(-1);
        animColor.setRepeatMode(ValueAnimator.REVERSE);
    
    
        ValueAnimator animScale = ValueAnimator.ofFloat(20f, 80f, 60f, 10f, 35f,55f,10f);
        animScale.setRepeatCount(-1);
        animScale.setRepeatMode(ValueAnimator.REVERSE);
        animScale.setDuration(5000);
        animScale.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                radius = (float) animation.getAnimatedValue();
            }
        });
    

    这里,我们使用ObjectAnimator 实现对color 属性的值按照ArgbEvaluator 这个类的规律在给定的颜色值之间变化,这个ArgbEvaluator 和我们之前定义的PointSinEvaluator一样,都是决定动画如何从初始值过渡到结束值的,只不过这个类是系统自带的,我们直接拿来用就可以,他可以实现各种颜色间的自由过渡。

    对radius 这个属性使用了ValueAnimator,使用了其ofFloat方法实现了一系列float值的变化;同时为其添加了动画变化的监听器,在属性值更新的过程中,我们可以将变化的结果赋给radius,这样就实现了半径动态的变化。

    这里radius 也可以使用和color相同的方式,只需要把ArgbEvaluator 替换为FloatEvaluator,同时修改动画的变化值即可;使用添加监听器的方式,只是为了介绍监听器的使用方法而已

    好了,到这里我们已经定义出了所有需要的动画,前面说过,属性动画也是可以组合使用的。因此,在动画启动的时候,同时播放这三个动画,就可以实现图中的效果了。

        animSet = new AnimatorSet();
        animSet.play(valueAnimator).with(animColor).with(animScale);
        animSet.setDuration(5000);
        animSet.setInterpolator(interpolatorType);
        animSet.start();
    

    PointAnimView 源码

    public class PointAnimView extends View {

    public static final float RADIUS = 20f;
    
    private Point currentPoint;
    
    private Paint mPaint;
    private Paint linePaint;
    
    private AnimatorSet animSet;
    private TimeInterpolator interpolatorType = new LinearInterpolator();
    
    /**
     * 实现关于color 的属性动画
     */
    private int color;
    private float radius = RADIUS;
    
    public PointAnimView(Context context) {
        super(context);
        init();
    }
    
    
    public PointAnimView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    
    public PointAnimView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
    
    
    public int getColor() {
        return color;
    }
    
    public void setColor(int color) {
        this.color = color;
        mPaint.setColor(this.color);
    }
    
    public float getRadius() {
        return radius;
    }
    
    public void setRadius(float radius) {
        this.radius = radius;
    }
    
    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.TRANSPARENT);
    
        linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        linePaint.setColor(Color.BLACK);
        linePaint.setStrokeWidth(5);
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
        if (currentPoint == null) {
            currentPoint = new Point(RADIUS, RADIUS);
            drawCircle(canvas);
    

    // StartAnimation();
    } else {
    drawCircle(canvas);
    }

        drawLine(canvas);
    }
    
    private void drawLine(Canvas canvas) {
        canvas.drawLine(10, getHeight() / 2, getWidth(), getHeight() / 2, linePaint);
        canvas.drawLine(10, getHeight() / 2 - 150, 10, getHeight() / 2 + 150, linePaint);
        canvas.drawPoint(currentPoint.getX(), currentPoint.getY(), linePaint);
    
    }
    
    public void StartAnimation() {
        Point startP = new Point(RADIUS, RADIUS);
        Point endP = new Point(getWidth() - RADIUS, getHeight() - RADIUS);
        final ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointSinEvaluator(), startP, endP);
        valueAnimator.setRepeatCount(-1);
        valueAnimator.setRepeatMode(ValueAnimator.REVERSE);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                currentPoint = (Point) animation.getAnimatedValue();
                postInvalidate();
            }
        });
    

    //
    ObjectAnimator animColor = ObjectAnimator.ofObject(this, “color”, new ArgbEvaluator(), Color.GREEN,
    Color.YELLOW, Color.BLUE, Color.WHITE, Color.RED);
    animColor.setRepeatCount(-1);
    animColor.setRepeatMode(ValueAnimator.REVERSE);

        ValueAnimator animScale = ValueAnimator.ofFloat(20f, 80f, 60f, 10f, 35f,55f,10f);
        animScale.setRepeatCount(-1);
        animScale.setRepeatMode(ValueAnimator.REVERSE);
        animScale.setDuration(5000);
        animScale.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                radius = (float) animation.getAnimatedValue();
            }
        });
    
    
        animSet = new AnimatorSet();
        animSet.play(valueAnimator).with(animColor).with(animScale);
        animSet.setDuration(5000);
        animSet.setInterpolator(interpolatorType);
        animSet.start();
    
    }
    
    private void drawCircle(Canvas canvas) {
        float x = currentPoint.getX();
        float y = currentPoint.getY();
        canvas.drawCircle(x, y, radius, mPaint);
    }
    
    
    public void setInterpolatorType(int type ) {
        switch (type) {
            case 1:
                interpolatorType = new BounceInterpolator();
                break;
            case 2:
                interpolatorType = new AccelerateDecelerateInterpolator();
                break;
            case 3:
                interpolatorType = new DecelerateInterpolator();
                break;
            case 4:
                interpolatorType = new AnticipateInterpolator();
                break;
            case 5:
                interpolatorType = new LinearInterpolator();
                break;
            case 6:
                interpolatorType=new LinearOutSlowInInterpolator();
                break;
            case 7:
                interpolatorType = new OvershootInterpolator();
            default:
                interpolatorType = new LinearInterpolator();
                break;
        }
    }
    
    
    @TargetApi(Build.VERSION_CODES.KITKAT)
    public void pauseAnimation() {
        if (animSet != null) {
            animSet.pause();
        }
    }
    
    
    public void stopAnimation() {
        if (animSet != null) {
            animSet.cancel();
            this.clearAnimation();
        }
    }
    

    }
    TimeInterpolator 介绍
    Interpolator的概念其实我们并不陌生,在补间动画中我们就使用到了。他就是用来控制动画快慢节奏的;而在属性动画中,TimeInterpolator 也是类似的作用;TimeInterpolator 继承自Interpolator。我们可以继承TimerInterpolator 以自己的方式控制动画变化的节奏,也可以使用Android 系统提供的Interpolator。

    下面都是系统帮我们定义好的一些Interpolator,我们可以通过setInterpolator 设置不同的Interpolator。

    系统自带Interpolator
    这里我们使用的Interpolator就决定了 前面我们提到的fraction。变化的节奏决定了动画所执行的百分比。不得不说,这么ValueAnimator的设计的确是很巧妙。

    XML 属性动画
    这里提一下,属性动画当然也可以使用xml文件的方式实现,但是属性动画的属性值一般会牵扯到对象具体的属性,更多是通过代码动态获取,所以xml文件的实现会有些不方便。

    使用方式:

    AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
    R.anim.property_animator);
    set.setTarget(myObject);
    set.start();
    xml 文件中的标签也和属性动画的类相对应。

    ValueAnimator —
    ObjectAnimator —
    AnimatorSet —
    这些就是属性动画的核心内容。现在使用属性动画的特性自定义动画应该不是难事了。其余标签的含义,结合之前的内容应该不难理解了。

    传统动画 VS 属性动画
    相较于传统动画,属性动画有很多优势。那是否意味着属性动画可以完全替代传统动画呢。其实不然,两种动画都有各自的优势,属性动画如此强大,也不是没有缺点。

    补间动画点击事件
    属性动画点击事件
    从上面两幅图比较可以发现,补间动画中,虽然使用translate将图片移动了,但是点击原来的位置,依旧可以发生点击事件,而属性动画却不是。因此我们可以确定,属性动画才是真正的实现了view的移动,补间动画对view的移动更像是在不同地方绘制了一个影子,实际的对象还是处于原来的地方。

    当我们把动画的repeatCount设置为无限循环时,如果在Activity退出时没有及时将动画停止,属性动画会导致Activity无法释放而导致内存泄漏,而补间动画却没有问题。因此,使用属性动画时切记在Activity执行 onStop 方法时顺便将动画停止。(对这个怀疑的同学可以自己通过在动画的Update 回调方法打印日志的方式进行验证)。

    xml 文件实现的补间动画,复用率极高。在Activity切换,窗口弹出时等情景中有着很好的效果。

    使用帧动画时需要注意,不要使用过多特别大的图,容易导致内存不足。

    好了,关于Android 动画的总结就到这里。

    最后 有兴趣的同学可查看github 源码欢迎star & fork

    展开全文
  • 这个原理类似于翻书动画-- 一个角色可以有很多造型,通过切换角色的造型,我们可以让他看起来像在做某种运动。 scratch内置的猫咪有两个造型,通过不停的切换两个造型,猫咪看起来像在走动-- 那么猫咪这样的...

    scratch里面角色的运动,是依靠切换造型来实现的。这个原理类似于翻书动画--

    一个角色可以有很多造型,通过切换角色的造型,我们可以让他看起来像在做某种运动。

    scratch内置的猫咪有两个造型,通过不停的切换两个造型,猫咪看起来像在走动--

    那么猫咪这样的运动方式有一点简单,我们可不可以做一些更加流畅真实的运动呢?比如--

    这个时候问题出现了,哪里去找这么合适的图片呢,而且要一张张的,顺起来还是一个完整的动作。

     

    这个时候我们有一个办法,就是直接找到一张运动的gif格式图片,gif可以用IE浏览器打开,如下图--

    然后用photoshop打开,这个时候ps会自动把gif图片的每一个图片分解到图层里面,如下图--

    每一个图层对应的是gif分解出来的每一个图片动作(类似于翻书动画的每一页的画面)。

    然后我们把每一张图片保存下来(保存为png图片)

    再分别上传到scratch角色里面的造型就可以了。

     

    这是我最后做出的效果图,是不是很酷。

    所以,如果以后想要做出炫酷的效果,就可以用这个办法了。

    方法总结:

    1.视频(找到合适的视频,剪切成适合大小的视频片段)

    2.gif图片(用合适的软件把视频转换成gif图片)

    3.Photoshop分解(用ps分解出gif内的每一个图片信息,再分别保存下来)

    4.scratch添加造型(把分别保存下来的图片,添加到造型里,重复切换下一个造型即可)

     

    注意事项:

    如果能直接找到gif图片,那就不需要找视频了,直接分解gif图片即可。

    gif图片里的内容,最好是除了你需要的,其他都是透明信息,否则图片还需要单独抠图。

    ps后保存为png格式图片,因为png格式可以保存图片的透明信息。

    非透明与透明得区别看下图--

    展开全文
  • 多张图片整合成连续动画

    千次阅读 2013-04-01 09:36:22
    把多张图片整合成连续动画,这恐怕是很多苹果开发者需要的功能。下面是单次播放和循环播放的代码。 animationImageView.animationImages = imageFrames;// imageFrames 是一个图片数组 animationImageView是一个...
  • 逐帧动画的工作原理很简单,其实就是将一个完整的动画拆分成一张张单独的图片,然后再将它们连贯起来进行播放,类似于动画片的工作原理。补间动画则是可以对View进行一系列的动画操作,包括淡入淡出、缩放、平移、...
  • 总的来说,安卓动画可以分为两类,最初的传统动画和Android3.0之后的属性动画。...实现原理是将一张张单独的图片连贯起来进行播放,从而在视觉上产生动画的效果,类似于某些制作gif动画的方式。创建
  • Android 动画

    2018-11-01 16:01:21
     帧动画动画中最容易实现的一种动画,其原理就是将一张张单独的图片连贯的播放出来从而产生视觉上的动画效果(图片资源决定了这是一个什么样的动画)  在我们实现动画的代码中会见到 android:oneshot="...
  • 1.通过改变图片来实现,比较连贯,但是需要好多张图片来实现,增加了http请求,但是很好用,主要用到css3和animation。 <!doctype html> <html lang="en"> <head> <meta charset="UTF-8...
  • 动画是最容易实现的一种动画,这种动画更多的依赖于完善的UI资源,他的原理就是将一张张单独的图片连贯的进行播放,从而在视觉上产生一种动画的效果;有点类似于某些软件制作gif动画的方式。 使用 <.
  • 逐帧动画(Frame Animation):原理就是将一个完整的动画拆成一张图片,然后将其连贯起来播放。类似动画片。帧动画具有非常大的灵活性,几乎可以表现任何想表现的内容,很适合表现细腻的动画。 补间动画(tweened ...
  • Android动画主要包括以下两种类型: View Animation(View动画) 在View动画框架中包括两种类型的动画: ...其实就是将一个完整的动画拆分成一张张单独的图片,然后再将它们连贯起来进行播放,类似于动画
  • 动画是最容易实现的一种动画,这种动画更多的依赖于完善的UI资源,他的原理就是将一张张单独的图片连贯的进行播放,从而在视觉上产生一种动画的效果;有点类似于某些软件制作gif动画的方式。 帧动画的实现方式有...
  • Android PowerImageView实现,可以播放动画的强大ImageView

    万次阅读 多人点赞 2013-10-25 08:36:03
    我个人是比较喜欢逛贴吧的,...我们都知道,在Android中如果想要显示一张图片,可以借助ImageView控件来完成,但是如果将一张GIF图片设置到ImageView里,它只会显示这张图片的第一帧,不会产生任何的动画效果。 那么
  • 在手机上去实现一些动画效果算是件比较炫酷的事情,因此Android系统在一开始的时候就给我们提供了两种实现动画效果的方式,逐帧动画(frame-by-frame animation)和补间动画(tweened animation)。逐帧动画的工作原理很...
  • Android 动画总结

    2018-03-15 11:07:44
    1.1、帧动画:帧动画是最容易实现的一种动画,这种动画更多的依赖于完善的UI资源,它的原理就是将一张张单独的图片连贯的进行播放,从而在视觉上产生一种动画的效果;有点类似于某些软件制作gif动画的方式。如上图中...
  • 文章目录帧动画View 动画(补间动画)属性动画...将一张张单独的图片连贯的进行播放 View 动画(补间动画) alpha(淡入淡出) translate(位移) scale(缩放大小) rotate(旋转) 属性动画(Android 3.0) ...
  • View 动画

    2018-05-17 16:10:09
    动画分类 Android动画总体分为两类:传统动画 和 Android3.0 之后出现的...帧动画是最容易实现的一种动画,这种动画更多的依赖于完善的UI资源,他的原理就是将一张张单独的图片连贯的进行播放,从而在视觉上产生...
  • 比如30帧每秒的视频,那么一秒就有30帧,每一帧都是静止的画面,就像一张照片,然后由这30张照片组成连贯动画用1秒的时间播放完。那么关键帧就是指动画变化过程中,关键动作所在的那一帧就是...
  • 最近需要做个图像采集的工作,其中一个步骤是需要将从摄像机采集的图像播放出来,由于摄像机采集的是一帧帧的图片,而播放的时候需要对播放速度进行控制,因此我考虑将图片放在一个缓冲区中,然后从缓存区中读取后...
  • Android 安卓动画动画(Frame)

    千次阅读 2018-08-30 16:27:49
    指的是每秒播放图片的数量,单位(fps),1 fps 是一帧,当帧速度达到25fps会形成连贯动画效果 类AnimationDrawable 用于创建逐帧动画的对象,由一系列Drawable对象定义,这些对象可以用作View对象的背景。创建逐帧...
  • 玩转gif图的第二课来了,这一次来聊一聊PS创建帧动画的工作流程和基础技能。你若静得太久,不妨一睹欢愉,让世界于你手中动起来!So,闲言少叙,直接开讲!(PS:推荐点击原图查看清晰大图哦)从理论上来说,PS的帧...
  • android动画

    2017-12-01 12:01:33
    总的来说,Android动画可以分为两类,最初的传统动画和Android3.0...帧动画是最容易实现的一种动画,这种动画更多的依赖于完善的UI资源,他的原理就是将一张张单独的图片连贯的进行播放, 从而在视觉上产生一种动画的效
  • Android动画

    2018-03-28 10:15:59
    Android动画分为两类:...(一)传统动画①帧动画(Frame Animation)帧动画的原理就是将一张张单独的图片连贯的进行播放,在视觉上产生一种动画的效果。帧动画实现代码:&lt;?xml version="1.0" en...
  • 制作动画

    2019-11-13 17:39:17
    其实制作一个动画很简单,动画的原理,就是让许多图片动起来,一张接着一张的速度播放起来,我们看的动画的原理就是一秒钟播放24张图片连贯起来所形成的图像就是动画,今天小编在这里给大家制作一个简单的动画,...
  • Tween动画提供了四种动画形式,即AlphaAnimation(渐变动画)、RotateAnimation(旋转动画)、ScaleAnimation(尺寸动画)、TranslateAnimation(位移动画),当然这些动画可以随意进行组合成组合动画AnimationSet。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,014
精华内容 805
关键字:

动画一张一张连贯图片