视图动画(View animation)
视图动画(View animation)
分为两类:补间动画(Tween animation)
、逐帧动画(Frame animation)
,两者都可以在XML中声明
一、帧动画
Frame animation
也叫Drawable动画
,Android3.0之前版本只有帧动画
在 XML 中定义的按顺序显示一系列图片的动画(如电影)。
文件位置:res/drawable/filename.xml
,编译后执指向AnimationDrawable
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot=["true" | "false"] >
<item
android:drawable="@[package:]drawable/drawable_resource_name"
android:duration="integer" />
</animation-list>
<!--
animation-list:必需。必须是根元素,包含一个或多个<item>元素
item:单帧动画
-->
使用如下,建议设置的图片不宜过多、过大,以防止因为内存不够出现OOM
val rocketImage: ImageView = findViewById(R.id.rocket_image)
rocketImage.setBackgroundResource(R.drawable.rocket_thrust)
// 设置Background和设置ImageResource是一样的效果:
rocketImage.setImageResource(R.drawable.rocket_thrust)
(rocketImage.background as AnimationDrawable).start()
// 或者这样也可以 (rocketImage.background as Animatable).start()
// 清除动画(android.view.View:clearAnimation())
rocketImage.clearAnimation()
二、补间动画
Tween animation
Android3.0之后增加了补间动画
民间有的也叫View动画
,是指android.view.animation
包下的类,只能被用来设置给 View,缺点是比如当控件移动之后,接收点击的控件的位置不会跟随移动
用于对图形执行 旋转`、淡出、移动、拉伸
文件位置:res/anim/filename.xml
,编译后指向Animatioin
① 基础使用
- xml的方式:
<?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"] >
<alpha
android:fromAlpha="float"
android:toAlpha="float" />
<scale
android:fromXScale="float"
android:toXScale="float"
android:fromYScale="float"
android:toYScale="float"
android:pivotX="float"
android:pivotY="float" />
<translate
android:fromXDelta="float"
android:toXDelta="float"
android:fromYDelta="float"
android:toYDelta="float" />
<rotate
android:fromDegrees="float"
android:toDegrees="float"
android:pivotX="float"
android:pivotY="float" />
<set>
...
</set>
</set>
使用:
val anim = AnimationUtils.loadAnimation(context, R.anim.traslate)
ivImage.startAnimation(anim)
- Java代码的方式:
// 单个使用
val alphaAnim = AlphaAnimation(0f, 1f)
alphaAnim.duration = 500
alphaAnim.fillAfter = true
alphaAnim.interpolator = AccelerateInterpolator()
ivImage.animation = alphaAnim
alphaAnim.start()
// 组合使用,true:共享插值器,false:不共享
val animationSet = AnimationSet(true)
animationSet.addAnimation(alphaAnim)
...
ivImage.startAnimation(animationSet)
Java类名 | 描述 |
---|---|
AnimationSet | 容纳其他动画元素(<alpha> 、<scale> 、<translate> 、<rotate> )或其他 <set> 元素的容器 |
AlphaAnimation | 淡入或淡出动画 |
ScaleAnimation | 大小调整动画。您可以通过指定 pivotX 和 pivotY ,来指定图片向外(或向内)扩展的中心点。例如,如果这两个值为 0、0(左上角),则所有扩展均向右下方向进行 |
TranslateAnimation | 竖直和/或水平移动。支持采用以下三种格式之一的以下属性:从 -100 到 100 的以“%”结尾的值,表示相对于自身的百分比;从 -100 到 100 的以“%p”结尾的值,表示相对于其父项的百分比;不带后缀的浮点值,表示绝对值 |
RotateAnimation | 旋转动画 |
② 常规使用介绍
-
Popwindow设置动画
val popupWindow = PopupWindow(ivImage, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) popupWindow.animationStyle = R.style.pop_anim
<!--pop_anim--> <style name="pop_anim"> <item name="android:windowEnterAnimation">@anim/pop_in</item> <item name="android:windowExitAnimation">@anim/pop_out</item> </style> <!--anim/pop_in.xml--> <set> <alpha android:fromAlpha="0" android:toAlpha="1" android:duration="2000" /> </set> <!--anim/pop_out.xml--> <set> <alpha android:fromAlpha="1" android:toAlpha="0" android:duration="2000" /> </set>
-
Activity设置页面跳转、退出动画效果
方式一:借助
overridePendingTransition(int entAnim, int exitAnim)
,在 startActivity 或 finish 后面。5.0以后用ActivityOptions
来实现过渡动画startActivity(new Intent(MainActivity.this,SecondActivity.class)); overridePendingTransition(R.anim.activity_in,R.anim.activity_out);
方式二:
style
,5.0以后用ActivityOptions
来实现过渡动画<?xml version="1.0" encoding="utf-8"?> <resources> <style name="AppTheme" parent="Theme.AppCompat.Light" > <!--设置windowAnimationStyle属性--> <item name="android:windowAnimationStyle">@style/ActivityAnim</item> </style> <style name="ActivityAnim"> <item name="android:activityOpenEnterAnimation">@anim/activity_in</item> <item name="android:activityOpenExitAnimation">@anim/activity_out</item> <item name="android:activityCloseEnterAnimation">@anim/activity_close_in</item> <item name="android:activityCloseExitAnimation">@anim/activity_close_out</item> </style> </resources>
-
给 ViewGroup 子控件添加动画
给ViewGroup指定
android:layoutAnimation
属性加上动画资源<!-- anm/anim_layout.xml --> <layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android" android:delay="0.2" android:animationOrder="reverse" android:animation="@anim/act_in"/> <!-- layout/act_main.xml --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:layoutAnimation="@anim/anim_layout"> <include layout="@layout/appbar_toolbar" /> ... </LinearLayout>
还可以通过代码指定,
LayoutAnimationController
对应xml中的layoutAnimation
val linearLayout = view.findViewById<LinearLayout>(R.id.id_item_btn) val anim = AnimationUtils.loadAnimation(context, R.anim.act_in) val controller = LayoutAnimationController(anim) controller.delay = 0.2f controller.order = LayoutAnimationController.ORDER_REVERSE linearLayout.layoutAnimation = controller
③ 补间动画原理
当前动画开始后,
View
会周期性调用它的getTransformation
方法不断获得动画结果,方法返回表示的是当前动画是否结束// Animation.java public boolean getTransformation(long currentTime, Transformation outTransformation){ //... if ((normalizedTime >= 0.0f || mFillBefore) && (normalizedTime <= 1.0f || mFillAfter)) { //... // 插值器 final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime); // 子类完成实际的动画逻辑 applyTransformation(interpolatedTime, outTransformation); } }
Transformation
:包含Matrix和Alpha字段,用来记录某次动画计算的变换结果// ViewGroup.java Transformation getChildTransformation() { if (mChildTransformation == null) { mChildTransformation = new Transformation(); } return mChildTransformation; }
调用栈追溯
// View.java boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { //... final Animation a = getAnimation(); if (a != null) { more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); //... } } private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, Animation a, boolean scalingRequired) { //... final Transformation t = parent.getChildTransformation(); boolean more = a.getTransformation(drawingTime, t, 1f); //... }