Android 动画之 View动画 和 帧动画

Android 动画可以分为三大类:

1>  View 动画 又称:补间 

2>  帧动画

3>  属性动画

 

==================【View 动画】=========================

有5种:

alpha                            渐变透明度动画效果
scale                            渐变尺寸伸缩动画效果
translate                        画面转换位置移动动画效果
rotate                           画面转移旋转动画效果
layoutAnimation           容器中的控件应用统一动画

 

 

首先,创建一个 目录 具体  步骤如下:

Android 动画之 View动画 和 帧动画_第1张图片

 

选:anim 目录

Android 动画之 View动画 和 帧动画_第2张图片

 

OK,看目录,创建一个 动画文件:set

Android 动画之 View动画 和 帧动画_第3张图片

 

命名为: my_animat

Android 动画之 View动画 和 帧动画_第4张图片

 

好了 ,我们在这个set  添加我们所需要的动画。

可以既是一个动画,也可以是多个动画的组合    

现在暂且先一个一个来,演示平移动画:

【translate】

看下动画目标View 的设置,用了一个TextView  注意:用了 宽高  是300px  像素,,,像素,,,像素

为什么用 px呢,会说到的  

 

然后动画 translate_ani.xml      注意:fillAfter="true"  View 最后会停留在动画结束的地方




    
    
    

 

看下原始的截图

Android 动画之 View动画 和 帧动画_第5张图片

 

看下Activity 中的layout:  activity_animator.xml





    


    

    

    

    

 

 

 

Activity的代码:

package com.leo.dicaprio.myutilapp.animator

import android.content.Context
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.animation.AnimationUtils
import android.widget.Toast
import com.leo.dicaprio.myutilapp.R
import kotlinx.android.synthetic.main.activity_animator.*
import org.jetbrains.anko.startActivity

class AnimatorActivity : AppCompatActivity() {

    companion object {
        fun launch(context: Context) {
            context.startActivity()
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_animator)
        tv_animator.setOnClickListener { Toast.makeText(this, "被单击了", Toast.LENGTH_LONG).show() }
        tv_animator1.setOnClickListener { startAni1() }
        tv_animator2.setOnClickListener { startAni2() }
        tv_animator3.setOnClickListener { startAni3() }
        tv_animator4.setOnClickListener { startAni4() }
    }


    /**
     *      平移动画
     * */
    private fun startAni1() {
        //先加载 平移动画
        val animation = AnimationUtils.loadAnimation(this, R.anim.translate_ani)
        tv_animator.startAnimation(animation)
    }

    

}

 

点击一下,动画过度效果就不生产 gif了,直接上最后结果

Android 动画之 View动画 和 帧动画_第6张图片

 

可以看到最后的结果。这时候 手机开了开发者模式的边界布局的。

分析下:

目标的 View 宽高是 300*300 像素,现在 动画 的 toXDelta和toYDelta都是300,表示向X Y 轴正方向移动 300像素。

为什么这么肯定 toXDelta 的单位是 像素呢?  从 截图看,可以理解为:目标 View 基于源点(左上角坐标)在XY方向 移动的距离,刚好是目标的宽高。。。

by the way ! 这个时候你点蓝色区域,是不会弹Taost,只有点击原始的位置,才会弹Toast。所以View动画并没有改变

View的属性。所以目标动画View是有点击事件的话,用View动画实现不了功能的。。。这个注意下。

 

好了,基本上可以理解完了。其实 translate 标签,是对应  TranslateAnimation() 

可以用它,代码改成:

    /**
     *      平移动画
     * */
    private fun startAni1() {
        //先加载 平移动画
//        val animation = AnimationUtils.loadAnimation(this, R.anim.translate_ani)
//        tv_animator.startAnimation(animation)

        //单位是像素
        val translateAnimation = TranslateAnimation(0F, 300F,0F , 300F)
        translateAnimation.fillAfter = true//停留在结束地方
        translateAnimation.duration = 500//时间
        tv_animator.startAnimation(translateAnimation)
    }

同样的效果!!!

另外,通过这个TranslateAnimation 还可以监听 动画的执行状态,比如:开始,结束,重复......

比如:

    /**
     *      平移动画
     * */
    private fun startAni1() {
        //先加载 平移动画
//        val animation = AnimationUtils.loadAnimation(this, R.anim.translate_ani)
//        tv_animator.startAnimation(animation)

        val translateAnimation = TranslateAnimation(0F, 300F, 0F, 300F)
        translateAnimation.setAnimationListener(object : Animation.AnimationListener {
            override fun onAnimationRepeat(animation: Animation?) {
                //动画重复
            }

            override fun onAnimationEnd(animation: Animation?) {
                //动画结束
            }

            override fun onAnimationStart(animation: Animation?) {
                //动画开始
            }

        })
        translateAnimation.fillAfter = false//停留在结束地方
        translateAnimation.duration = 500//时间
        tv_animator.startAnimation(translateAnimation)
    }

 

【alpha】

透明比较简单。。。。上alpha_ani.xml 代码:




    
    
    

 

Activity 引用

    /**
     *      透明动画
     * */
    private fun startAni2() {
        //先加载 透明动画
        val animation = AnimationUtils.loadAnimation(this, R.anim.alpha_ani)
        tv_animator.startAnimation(animation)

        /*
        *       或者
        * */
        val alphaAnimation = AlphaAnimation(1.0F, 0F)
        alphaAnimation.fillAfter = true
        alphaAnimation.duration = 5000
        tv_animator.startAnimation(alphaAnimation)
    }

 

【Rotate】

旋转,一般四个参数

fromDegrees    开始时的角度
toDegrees      结束时角度 ,正代表顺时针
pivotX         旋转中心轴点 X坐标 不指定 默认是View 左上角 X坐标   单位像素
pivotY         旋转中心轴点 Y坐标 不指定 默认是View 左上角 Y坐标   单位像素

 

不说废话,上   目标View,哈哈,同样是一个TextView,同样是 300*300 px

    

 

 

上动画文件:anim /rotate_ani.xml




    
    
    

 

注意!!!   pivotX 和 pivotY  是150,刚好是TextView宽高的一半。

Activity调用:

    /**
     *      旋转动画
     * */
    private fun startAni3() {
        //先加载 旋转动画
        val animation = AnimationUtils.loadAnimation(this, R.anim.rotate_ani)
        tv_animator.startAnimation(animation)

        /*
        *       或者
        * */
        val rotateAnimation = RotateAnimation(0F, 180F, 150F, 150F)
        rotateAnimation.fillAfter = true
        rotateAnimation.duration = 5000
        tv_animator.startAnimation(rotateAnimation)
    }

测试的结果,是在TextView是 300*300 px时,

1>   pivotX和pivotY都为150,旋转中心为 TextView的中心

1>   pivotX和pivotY都为0,    旋转中心为 TextView的左上角

所以,结论是:这个旋转圆点坐标,是基于目标View左上角(0,0)坐标的。

 

 

【Scale】

缩放。。。。。。

fromXScale,fromYScale   X Y 方向  缩放起始值
toXScale, toYScale     X Y 方向  缩放结束值
pivotX ,pivotY          X Y 方向  缩放中心值   中心点也是和上面的基准规则一样

代码都不贴了,都一样的·原理。。。。。

 

============【多个动画一起播放或者按顺序播放】=============

多个动画同时播放

my_toget__animat.xml代码:   多个动画(透明,旋转,缩放)一起



    
    

    
    

    
    

 

view层的处理:运行结果是 (透明,旋转,缩放)同事进行

private fun animationSet(){
        //加载 
        val animation = AnimationUtils.loadAnimation(this, R.anim.my_toget__animat)
        tv_animator_view.startAnimation(animation)
    }

 

这个可以不用 xml类型,可以用代码动态,比如:

private fun animationSet(){
        val rotateAnimation = RotateAnimation(0F, 180F, 150F, 150F)
        val alphaAnimation = AlphaAnimation(1.0F, 0F)
        val scaleAnimation = ScaleAnimation(0F, 1F, 0F, 1F, 150F, 150F)

        //多个动画 放进 AnimationSet 
        val animationSet = AnimationSet(true)
        animationSet.addAnimation(rotateAnimation)
        animationSet.addAnimation(alphaAnimation)
        animationSet.addAnimation(scaleAnimation)
        animationSet.duration = 5000
        tv_animator_view.startAnimation(animationSet)
    }

动态代码设置 AnimationSet 集合,把需要的动画放进去,效果是一样的

 

 

多个动画按顺序播放

顺序播放的思路,在xml是用延时法  通过 startOffset 指定延迟执行动画

比如:




    
    

    
    
    
    

 

加载设置用法是一样的,就不贴了

 

使用代码设置  顺序,监听第一个动画完成,再进行第2个动画

private fun animationOrder(){
        val rotateAnimation = RotateAnimation(0F, 180F, 150F, 150F)
        rotateAnimation.fillAfter = true
        rotateAnimation.duration = 5000
        rotateAnimation.setAnimationListener(object :Animation.AnimationListener{
            override fun onAnimationRepeat(animation: Animation?) {
                //动画重复
            }

            override fun onAnimationEnd(animation: Animation?) {
                //动画结束
                val alphaAnimation = AlphaAnimation(1.0F, 0F)
                alphaAnimation.fillAfter = true
                alphaAnimation.duration = 5000
                tv_animator_view.startAnimation(alphaAnimation)
            }

            override fun onAnimationStart(animation: Animation?) {
                //动画开始

            }

        })
        tv_animator_view.startAnimation(rotateAnimation)
    }

 

 

=======【layoutAnimation】==========

作用于 ViewGroup,为一个ViewGroup指定一个动画,他的所有子元素,出厂时都会具有这个动画效果

比如在RecycleView指定时,每个item都会有

比如在ViewGroup指定时,每个子View都会有

首先,创建 layoutAnimation :  anim/layout_animation.xml




    

创建 layoutAnimation :  anim/ alpha.xml




    
    
    

 

父布局 layout文件:



        


        

        

    

 

注意!!   父布局的 visibility = invisible的,当父布局变成:visible后,三个子view 就会显示出来

当然,出现的形式是以动画的形式的。。。

在代码里调用:

private fun layoutAnimation() {
        tv_animator_contain.visibility = View.VISIBLE
    }

直接把父布局显示出来即可,所有子View的出现,都会有动画效果。。。。

你也可以在父布局  layout不设置,通过  LayoutAnimationController

直接上代码:

private fun layoutAnimation() {
        val loadAnimation = AnimationUtils.loadAnimation(this, R.anim.alpha_ani)
        val animationController = LayoutAnimationController(loadAnimation)
        animationController.delay = 0.1F
        animationController.order = LayoutAnimationController.ORDER_NORMAL
        tv_animator_contain.layoutAnimation = animationController
        tv_animator_contain.visibility = View.VISIBLE
    }

注意!!!!!!!

代码引用的是 alpha_ani.xml,直接引用动画文件,并不是引用  layoutAnimation 

 

==================【帧动画】=========================

首先说下,帧动画,是类似于视频播放那样,一秒显示26张图片,肉眼看到的效果就是视频了。

帧动画,会一下子把所有图片加载内存,然后每隔设定duration,就展示下一张图片。。。

不推荐!!!因为非常消耗内存!!!!!!

首先,创建帧动画,是在 drawable目录下的  。。。

Android 动画之 View动画 和 帧动画_第7张图片

然后选择  animation-list

Android 动画之 View动画 和 帧动画_第8张图片

 

然后 

Android 动画之 View动画 和 帧动画_第9张图片

 

在控件里使用:

    /**
     *      帧动画
     * */
    private fun startFrameAni() {
        //先设置
        tv_animator_view.setBackgroundResource(R.drawable.frame_animation)
        //再获取  强转成 AnimationDrawable
        val background = tv_animator_view.background as AnimationDrawable
        //开启动画
        background.start()
    }

再说一次,这个如果 图片过多的话,容易导致OOM

如果非得 使用帧动画,可以  把 需要的 drawable的ID全部放进一个List里面

然后自己写一个定时器(比如用Handler),隔多少秒,通过ID获取drawable  展示一个图片,这样避免一下子把所有图片加载到内存。。。。

好了。。。。。。这边就到这里

 

 

下篇写:属性动画

上面代码亲测没问题,,,,有问题请留言指正,,,谢谢!!!!

 

你可能感兴趣的:(Android 动画之 View动画 和 帧动画)