Android 动画可以分为三大类:
1> View 动画 又称:补间
2> 帧动画
3> 属性动画
==================【View 动画】=========================
有5种:
alpha 渐变透明度动画效果
scale 渐变尺寸伸缩动画效果
translate 画面转换位置移动动画效果
rotate 画面转移旋转动画效果
layoutAnimation 容器中的控件应用统一动画
首先,创建一个 目录 具体 步骤如下:
选:anim 目录
OK,看目录,创建一个 动画文件:set
命名为: my_animat
好了 ,我们在这个set 添加我们所需要的动画。
可以既是一个动画,也可以是多个动画的组合
现在暂且先一个一个来,演示平移动画:
【translate】
看下动画目标View 的设置,用了一个TextView 注意:用了 宽高 是300px 像素,,,像素,,,像素
为什么用 px呢,会说到的
<TextView
android:id="@+id/tv_animator"
android:layout_width="300px"
android:layout_height="300px"
android:background="@color/color_00a3f3"
android:text="animator"
android:textColor="@color/color_7e4513"
android:gravity="center"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
然后动画 translate_ani.xml 注意:fillAfter="true" View 最后会停留在动画结束的地方
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<!-- 平移 对应 TranslateAnimation
fromXDelta,fromYDelta 起始时X,Y座标,如果是0,0,就从远处开启
toXDelta, toYDelta 动画结束时X,Y的座标 这个坐标是相对于 原始位置(0,0)的
看下 toXDelta toYDelta 和TextView 宽高同是 300
-->
<translate
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="300"
android:toYDelta="300"
android:duration="500">
</translate>
</set>
看下原始的截图
看下Activity 中的layout: activity_animator.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".animator.AnimatorActivity">
<TextView
android:id="@+id/tv_animator"
android:layout_width="300px"
android:layout_height="300px"
android:background="@color/color_00a3f3"
android:text="目标动画"
android:textColor="@color/color_7e4513"
android:gravity="center"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:id="@+id/tv_animator1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/dp10"
android:layout_marginTop="@dimen/dp100"
android:text="平移动画"
android:background="@color/color_999999"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_animator"/>
<TextView
android:id="@+id/tv_animator2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/dp10"
android:layout_marginTop="@dimen/dp10"
android:text="透明动画"
android:background="@color/color_999999"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_animator1"/>
<TextView
android:id="@+id/tv_animator3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/dp10"
android:layout_marginTop="@dimen/dp10"
android:text="旋转动画"
android:background="@color/color_999999"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_animator2"/>
<TextView
android:id="@+id/tv_animator4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/dp10"
android:layout_marginTop="@dimen/dp10"
android:text="缩放动画"
android:background="@color/color_999999"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_animator3"/>
</android.support.constraint.ConstraintLayout>
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<AnimatorActivity>()
}
}
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了,直接上最后结果
可以看到最后的结果。这时候 手机开了开发者模式的边界布局的。
分析下:
目标的 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 代码:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<!--透明
fromAlpha:开始时透明度 0.0- 1.0 0.0全透明 1.0不透明
toAlpha: 结束时透明度 0.0- 1.0
duration:动画持续时间 单位 毫秒
fillAfter:动画结束后是否停留在结束位置,true停留
-->
<alpha android:fromAlpha="1"
android:toAlpha="0"
android:duration="10000"
>
</alpha>
</set>
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
<TextView
android:id="@+id/tv_animator"
android:layout_width="300px"
android:layout_height="300px"
android:background="@color/color_00a3f3"
android:text="目标动画"
android:textColor="@color/color_7e4513"
android:gravity="center"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
上动画文件:anim /rotate_ani.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<!--
fromDegrees 开始时的角度
toDegrees 结束时角度 ,正代表顺时针
pivotX 旋转中心轴点 X坐标 不指定 默认是View 左上角 X坐标
pivotY 旋转中心轴点 Y坐标 不指定 默认是View 左上角 Y坐标
-->
<rotate android:fromDegrees="0"
android:toDegrees="180"
android:pivotY="150"
android:pivotX="150"
android:duration="5000">
</rotate>
</set>
注意!!! 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代码: 多个动画(透明,旋转,缩放)一起
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha android:fromAlpha="1"
android:toAlpha="0"
android:duration="5000">
</alpha>
<rotate android:fromDegrees="0"
android:toDegrees="180"
android:pivotY="150"
android:pivotX="150"
android:duration="5000">
</rotate>
<scale android:fromXScale="0"
android:fromYScale="0"
android:toXScale="1"
android:toYScale="1"
android:pivotX="150"
android:pivotY="150"
android:duration="5000">
</scale>
</set>
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 指定延迟执行动画
比如:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha android:fromAlpha="0"
android:toAlpha="1"
android:duration="3000"
android:fillAfter="true">
</alpha>
<!--第2个动画延迟3000毫秒-->
<rotate
android:startOffset="3000"
android:fromDegrees="0"
android:toDegrees="180"
android:pivotY="150"
android:pivotX="150"
android:duration="3000"
android:fillAfter="true">
</rotate>
</set>
加载设置用法是一样的,就不贴了
使用代码设置 顺序,监听第一个动画完成,再进行第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
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:delay="1"
android:animationOrder="random"
android:animation="@anim/alpha_ani">
<!--
delay: 每个子View时间间隔 如果有多个子view的话,如果设定的动画周期是 duration = 1000毫秒,
如果 delay=0.1,则下一个子View 会在100(duration * delay)毫秒执行动画
animationOrder:子view经常顺序,normal是最前面的先进来,
reverse是最后的先进来
random 正看英文就知道。。。。哈哈
顺序就是View.getChildView(index) 里面的这个index
-->
</layoutAnimation>
创建 layoutAnimation : anim/ alpha.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<!--透明
fromAlpha:开始时透明度 0.0- 1.0 0.0全透明 1.0不透明
toAlpha: 结束时透明度 0.0- 1.0
duration:动画持续时间 单位 毫秒
fillAfter:动画结束后是否停留在结束位置,true停留
-->
<alpha android:fromAlpha="0"
android:toAlpha="1"
android:duration="5000"
>
</alpha>
</set>
父布局 layout文件:
<android.support.constraint.ConstraintLayout
android:id="@+id/tv_animator_contain"
android:layout_width="0dp"
android:layout_height="300px"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layoutAnimation="@anim/layout_animation"
android:visibility="invisible"
>
<TextView
android:id="@+id/tv_animator_view"
android:layout_width="300px"
android:layout_height="300px"
android:background="@color/color_00a3f3"
android:text="目标动画1"
android:textColor="@color/color_7e4513"
android:gravity="center"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/tv_animator_view2"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_chainStyle="spread"/>
<TextView
android:id="@+id/tv_animator_view2"
android:layout_width="300px"
android:layout_height="300px"
android:background="@color/color_00a3f3"
android:text="目标动画1"
android:textColor="@color/color_7e4513"
android:gravity="center"
app:layout_constraintLeft_toRightOf="@id/tv_animator_view"
app:layout_constraintRight_toLeftOf="@id/tv_animator_view3"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_chainStyle="spread"/>
<TextView
android:id="@+id/tv_animator_view3"
android:layout_width="300px"
android:layout_height="300px"
android:background="@color/color_00a3f3"
android:text="目标动画1"
android:textColor="@color/color_7e4513"
android:gravity="center"
app:layout_constraintLeft_toRightOf="@id/tv_animator_view2"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_chainStyle="spread"/>
</android.support.constraint.ConstraintLayout>
注意!! 父布局的 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目录下的 。。。
然后选择 animation-list
然后
在控件里使用:
/**
* 帧动画
* */
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 展示一个图片,这样避免一下子把所有图片加载到内存。。。。
好了。。。。。。这边就到这里
下篇写:属性动画
上面代码亲测没问题,,,,有问题请留言指正,,,谢谢!!!!