Android 基础知识-动画相关

℡╲_俬逩灬. 提交于 2019-12-12 09:07:18

常用动画View动画(补间动画)、属性动画与帧动画

View 动画

通过对View 不断做【图像变换】(平移、缩放、旋转、透明度)产生动画效果。

可以通过 xml/java代码来创建

1、支持4中动画效果

TranslateAnimation 平移动画 <translate>
ScaleAnimation 缩放动画 <scale>
RotateAnimation 旋转动画 <rotate>
AlphaAnimation 透明度动画 <alpha>

2、xml/java代码来创建

1)xml创建View动画
xml文件目录:res/anim/filename.xml

一组动画:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
	android:interpolator="@android:anim/decelerate_interpolator"
	android:shareInterpolator="false">

	<translate
		android:duration="@android:integer/config_shortAnimTime"
		android:fromXDelta="0"
		android:toXDelta="0"
		android:fromYDelta="0%"
		android:toYDelta="100%" />
	<scale
		android:duration="@android:integer/config_shortAnimTime"
		android:fromXScale="100%"
		android:toXScale="100%"
		android:fromYScale="0%"
		android:toYScale="100%" />
	<rotate android:fromDegrees="90" android:toDegrees="0"
		android:pivotX="50%" android:pivotY="50%"
		android:interpolator="@interpolator/decelerate_quint"
		android:fillEnabled="true"
		android:fillBefore="true" android:fillAfter="true"
		android:duration="@android:integer/config_mediumAnimTime" />

	<alpha
		android:duration="@android:integer/config_shortAnimTime"
		android:fromAlpha="1.0"
		android:toAlpha="0.0" />
</set>

单个动画:

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
		android:fromDegrees="0"
		android:pivotX="50%"
		android:pivotY="50%"
		android:toDegrees="720" />

使用动画:

Button btn = findViewById(R.id.button1);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.animation_file);
btn.startAnimation(animation);

2)代码创建 View动画

Button btn = findViewById(R.id.button1);
AlphaAnimation alphaAnim = new AlphaAnimation(0, 1);
alphaAnim.setDuration(300);
alphaAnim.setInterpolator(new DecelerateInterpolator());
alphaAnim.setRepeatCount(0);
alphaAnim.setFillAfter(false);
//启动单个动画
btn.startAnimation(alphaAnim);
//动画组
final AnimationSet set = new AnimationSet(false);
set.addAnimation(alphaAnim);
btn.startAnimation(set);

3)android:interpolator
动画插值器,插值器影响动画的速度。
默认为@android:anim/accelerate_decelerate_interpolator 加速减速插值器。

4)android:shareInterpolator
表示集合中的动画 是否和集合共享同一个插值器
如果集合不指定插值器,那么子动画需要单独指定所需的插值器或者使用默认值。

5)android:duration 动画持续时间

6)Android:fillAfter 动画结束后,View是否停留在结束位置
true表示停留在结束位置,false不停留

7)自定义View动画

/**
 * 3D缩放动画,围绕 y轴旋转,同时沿着 z轴平移,从而实现类似3D的效果
 */
public class Rotate3dAnimation extends Animation {
	private final float mFromDegrees;
	private final float mToDegrees;
	private final float mCenterX;
	private final float mCenterY;
	private final float mDepthZ;
	private final boolean mReverse;
	private Camera mCamera;

	public Rotate3dAnimation(float fromDegrees, float toDegrees,
			float centerX, float centerY, float depthZ, boolean reverse) {
		mFromDegrees = fromDegrees;
		mToDegrees = toDegrees;
		mCenterX = centerX;
		mCenterY = centerY;
		mDepthZ = depthZ;
		mReverse = reverse;
	}

	@Override
	public void initialize(int width, int height, int parentWidth, int parentHeight) {
		super.initialize(width, height, parentWidth, parentHeight);
		mCamera = new Camera();
	}

	@Override
	protected void applyTransformation(float interpolatedTime, Transformation t) {
		super.applyTransformation(interpolatedTime, t);
		final float fromDegrees = mFromDegrees;
		//根据插值器的值,获取要旋转的角度
		float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
		final float centerX = mCenterX;
		final float centerY = mCenterY;
		final Camera camera = mCamera;
		final Matrix matrix = t.getMatrix();//获取动画目标控件的矩阵
		camera.save();
		if (mReverse) {//根据插值器获取z轴移动距离
			camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
		} else {
			camera.translate(0.0f, 0.0f, mDepthZ * (1 - interpolatedTime));
		}
		camera.rotateY(degrees);//根据插值器旋转一定角度
		camera.getMatrix(matrix);//把动画控件矩阵传入camera
		camera.restore();
		
		matrix.preTranslate(-centerX, -centerY);
		matrix.postTranslate(centerX, centerY);
	}
}

帧动画

帧动画是播放一组预先定义好的图片。
res/ anim /frame_animation.xml

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
	android:oneshot="false">
	<item android:drawable="@drawable/image1" android:duration="500"/>
	<item android:drawable="@drawable/image2" android:duration="500"/>
	<item android:drawable="@drawable/image3" android:duration="500"/>
</animation-list>

Button btn = findViewById(R.id.button1);
btn.setBackgroundResource(R.drawable.frame_animation);
AnimationDrawable drawable = (AnimationDrawable) btn.getBackground();
drawable.start();

帧动画比较容易引起OOM,使用帧动画时,应尽量避免使用太多/尺寸较大的图片

View动画的特殊使用场景

1、 LayoutAnimation

LayoutAnimation 作用于ViewGroup,为 ViewGroup指定一个动画
实现 子元素出场动画效果

1)定义 LayoutAnimation
res/anim/anim_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation 
	xmlns:android="http://schemas.android.com/apk/res/android" 
	android:delay="0.5"
	android:animationOrder="normal"
	android:animation="@anim/anim_item"/>

android:delay:表示子元素开始动画的时间延迟百分比

比如,子元素入场动画的时间周期为300ms,那么 android:delay="0.5"
	表示每个子元素都需要延迟 300*0.5 == 150ms 才能播放入场动画。
	
	总体来说,第一个子元素延迟 150ms 开始播放入场动画,
			  第二个子元素延迟 300ms 开始播放入场动画,依此类推。

android:animationOrder
子元素的动画顺序,有三种选项:normal、reverse、random
normal:表示顺序显示
reverse:表示逆向显示,排在后面的子元素先开始播放入场动画。
random:随机播放入场动画

android:animation:为子元素指定具体的入场动画

2)为子元素指定具体的入场动画
res/anim/anim_item.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
	android:duration="300"
	android:interpolator="@android:anim/accelerate_interpolator"
	android:shareInterpolator="true">

	<translate
		android:fromXDelta="500"
		android:toXDelta="0"/>
	<alpha
		android:fromAlpha="0.0"
		android:toAlpha="1.0" />
</set>

3)为ViewGroup 指定 android:layoutAnimation 属性
android:layoutAnimation="@anim/anim_layout"

xml中指定的方式

<android.support.v7.widget.RecyclerView
	android:id="@+id/recycler_view"
	android:layoutAnimation="@anim/anim_layout"
	android:layout_width="match_parent"
	android:layout_height="match_parent"/>

LayoutAnimationController 实现

RecyclerView recyclerView = findViewById(R.id.recycler_view);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_item);
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
recyclerView.setLayoutAnimation(controller);
4、 页面切换动画

1)Activity的切换动画

overridePendingTransition(int enterAnim, int exitAnim);

必须在 startActivity(Intent) / finish() 【之后】调用才能生效

2)Fragment切换动画
通过 FragmentTransaction 中的 setCustomAnimations();来添加切换动画。

5、 属性动画
ValueAnimator、ObjectAnimator、AnimatorSet

属性动画 可以对任意对象的属性,进行动画,不仅限于View
效果是:在一个时间间隔内,完成对象从要给属性值到另一个属性值的改变

1)代码实现属性动画

ObjectAnimator.ofFloat(myObject, "translationY", -myObject.getHeight()).start();	
ValueAnimator colorAnim = ObjectAnimator.ofInt(this, "backgroundColor", 0xFFFF8080, 0Xff8080ff);
colorAnim.setDuration(3000)	;
colorAnim.setEvaluator(new ArgbEvaluator());
colorAnim.setRepeatCount(ValueAnimator.INFINITE);
colorAnim.setRepeatMode(ValueAnimator.REVERSE);
colorAnim.start();

AnimationSet set = new AnimationSet();
set.playTogether(
	ObjectAnimator.ofFloat(myView, "rotationX", 0, 360),
	ObjectAnimator.ofFloat(myView, "rotationY", 0, 180)
);
set.setDuration(5000).start();

2)xml实现属性动画
属性动画xml需要定义在 res/animator/目录下
res/ animator /anim_property.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
	android:ordering="together">
	<objectAnimator 
		android:propertyName="string"
		android:duration="int"
		android:valueFrom="float | int | color"
		android:valueTo="float | int | color"
		android:startOffset="int"
		android:repeatCount="int"
		android:repeatMode="restart"
		android:valueType="colorType"
		/>
	<animator
		android:duration="int"
		android:valueFrom="float | int | color"
		android:valueTo="float | int | color"
		android:startOffset="int"
		android:repeatCount="int"
		android:repeatMode="reverse"
		android:valueType="intType"/>
</set>

在代码中使用xml:

Animator animator = AnimatorInflater.loadAnimator(this, R.animator.anim_property);
animator.setTarget(mIvGlideTest);
animator.start();

说明:
<objectAnimator> 标签,对应 ObjectAnimator
<animator> 标签, 对应 ValueAnimator

android:ordering: 默认值 together
together: 表示 集合中子动画同时播放
sequentially:表示动画集合中 子动画按前后顺序依次播放

android:startOffset:动画的延迟时间,当动画开始后,延迟多少毫秒开始真正播放此动画

View动画与属性动画区别

View动画,操作的是控件的影像,控件本身属性没有发生变化。
属性动画,修改的时对象的属性,对象本身会被改变。

插值器和估值器理解

插值器:根据时间流逝的百分比,来计算当前属性值改变的百分比
(根据时间流逝比例,计算属性改变的百分比)

自定义插值器,需要实现 Interpolator 接口,或者 TimeInterpolator 接口

估值器:根据当前属性改变的百分比,来计算改变后的属性值
(根据属性改变的百分比,计算改变后的属性值)
IntEvaluator、FloatEvaluator

属性动画监听器:AnimatorUpdateListener、AnimatorListener

public static interface AnimatorUpdateListener {
	void onAnimationUpdate(ValueAnimator animation);
}

属性动画【每播放一帧】,onAnimationUpdate就会被调用一次

推荐阅读:
Android自定义控件三部曲文章索引
《Android开发艺术探索》 第七章 Android动画深入分析

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!