Duang Duang Duang — 给视图加特效(动画)

/ 0评 / 0

前言

想要让自己的app能Duang的一下变得绚丽点,动画效果是必不可少的,还是老样子,前辈们已经总结出来的精髓就不再重复介绍了,直接贴出来自harvic880925的博客(传送门),这几篇博客主要系统的介绍了视图动画和属性动画的用法,包括自定义插值器(Interpolator)以及Evaluator等高级操作。本篇博客是以前辈的博客为基础的,介绍的是给ViewGroup动态增加控件时的动画。

Duang Duang Duang对比图

默认(没有动画效果)

default

默认动画效果

DuangDuangDuang1

自定义动画效果

DuangDuangDuang2

具体实现

要实现这种效果,需要使用的是LayoutTransition,如果想要给ViewGroup实现默认的动画效果是很简单的,有两种实现方法,可以在布局文件中使用下面的属性

android:animateLayoutChanges="true"

或者在代码中给对应的ViewGroup使用setLayoutTransition(LayoutTransition )设置。如下,如果不设置动画,采用默认实现,效果和第一种方法一样。

// 实例化LayoutTransition属性

mLayoutTransition = new LayoutTransition();

mGridLayout.setLayoutTransition(mLayoutTransition);

如果我们想使用使用自定义的动画效果,可以直接给LayoutTransition使用LayoutTransition.setAnimator(int transitionType, Animator animator)设置动画,其中第一个参数transitionType的取值可以为以下四种。

详细代码

布局文件是一个按钮以及一个GridLayout按照线性布局排列。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <Button
        android:id="@+id/add"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="add button" />
    <GridLayout
        android:id="@+id/grid"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:animateLayoutChanges="true" >
    </GridLayout>
</LinearLayout>

Activity代码片,关键是createCustomAnimations()方法,在这个方法中,我分别为上面说的四种情况设置了动画。

package com.jay.demo2;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.Keyframe;
import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.GridLayout;

public class MainActivity extends ActionBarActivity {

	private Button mAddBtn;
	private GridLayout mGridLayout;
	private LayoutTransition mLayoutTransition;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.fragment_main);
		// 实例化控件
		mAddBtn = (Button) findViewById(R.id.add);
		mGridLayout = (GridLayout) findViewById(R.id.grid);
		mAddBtn.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				addBtn();
			}
		});
		// 实例化LayoutTransition属性
		mLayoutTransition = new LayoutTransition();
		// 设置GridLayout的基本属性
		mGridLayout.setColumnCount(5);
		mGridLayout.setLayoutTransition(mLayoutTransition);
		// 设置动画
		createCustomAnimations(mLayoutTransition);
	}

	/**
	 * 添加按钮,并给按钮添加点击时间,点击删除按钮
	 */
	private void addBtn() {
		Button btn = new Button(this);
		mGridLayout.addView(btn, 0);
		btn.setText(mGridLayout.getChildCount() + "");
		btn.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				mGridLayout.removeView(v);
			}
		});
	}

	/**
	 * 为LayoutTransition设置动画
	 * 
	 * @param transition
	 *            传入的动画
	 */
	private void createCustomAnimations(LayoutTransition transition) {
		// Changing while Adding
		PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left", 0, 1);
		PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0, 1);
		PropertyValuesHolder pvhRight = PropertyValuesHolder.ofInt("right", 0,
				1);
		PropertyValuesHolder pvhBottom = PropertyValuesHolder.ofInt("bottom",
				0, 1);
		PropertyValuesHolder pvhScaleX = PropertyValuesHolder.ofFloat("scaleX",
				1f, 0f, 1f);
		PropertyValuesHolder pvhScaleY = PropertyValuesHolder.ofFloat("scaleY",
				1f, 0f, 1f);
		ObjectAnimator customChangingAppearingAnim = ObjectAnimator
				.ofPropertyValuesHolder(this, pvhScaleX, pvhLeft, pvhTop,
						pvhRight, pvhBottom, pvhScaleY)
				.setDuration(
						transition
								.getDuration(LayoutTransition.CHANGE_APPEARING));
		customChangingAppearingAnim.addListener(new AnimatorListenerAdapter() {
			public void onAnimationEnd(Animator anim) {
				View view = (View) ((ObjectAnimator) anim).getTarget();
				view.setScaleX(1f);
				view.setScaleY(1f);
			}
		});

		// Changing while Removing
		Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
		Keyframe kf1 = Keyframe.ofFloat(.9999f, 360f);
		Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
		PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe(
				"rotation", kf0, kf1, kf2);
		ObjectAnimator customChangingDisappearingAnim = ObjectAnimator
				.ofPropertyValuesHolder(this, pvhLeft, pvhTop, pvhRight,
						pvhBottom, pvhRotation)
				.setDuration(
						transition
								.getDuration(LayoutTransition.CHANGE_DISAPPEARING));
		customChangingDisappearingAnim
				.addListener(new AnimatorListenerAdapter() {
					public void onAnimationEnd(Animator anim) {
						View view = (View) ((ObjectAnimator) anim).getTarget();
						view.setRotation(0f);
					}
				});

		// Adding
		ObjectAnimator customAppearingAnim = ObjectAnimator.ofFloat(null,
				"rotationY", 90f, 0f).setDuration(
				transition.getDuration(LayoutTransition.APPEARING));
		customAppearingAnim.addListener(new AnimatorListenerAdapter() {
			public void onAnimationEnd(Animator anim) {
				View view = (View) ((ObjectAnimator) anim).getTarget();
				view.setRotationY(0f);
			}
		});

		// Removing
		ObjectAnimator customDisappearingAnim = ObjectAnimator.ofFloat(null,
				"rotationX", 0f, 90f).setDuration(
				transition.getDuration(LayoutTransition.DISAPPEARING));
		customDisappearingAnim.addListener(new AnimatorListenerAdapter() {
			public void onAnimationEnd(Animator anim) {
				View view = (View) ((ObjectAnimator) anim).getTarget();
				view.setRotationX(0f);
			}
		});

		transition.setAnimator(LayoutTransition.DISAPPEARING,
				customDisappearingAnim);
		transition.setAnimator(LayoutTransition.APPEARING, customAppearingAnim);
		transition.setAnimator(LayoutTransition.CHANGE_APPEARING,
				customChangingAppearingAnim);
		transition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING,
				customChangingDisappearingAnim);
	}
}

上面所写的四种情况中,有两种情况非常特殊,就是LayoutTransition.CHANGE_APPEARING 以及 LayoutTransition.CHANGE_DISAPPEARING动画设置方法,必须和上面设置的方法一样,不然不会显示出预期的效果。

LayoutTransition.CHANGE_APPEARING得使用如下方法。

//Changing while Adding
PropertyValuesHolder pvhLeft =  PropertyValuesHolder.ofInt("left", 0, 1);
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0, 1);
PropertyValuesHolder pvhRight = PropertyValuesHolder.ofInt("right", 0, 1);
PropertyValuesHolder pvhBottom =  PropertyValuesHolder.ofInt("bottom", 0, 1);
PropertyValuesHolder pvhScaleX = ropertyValuesHolder.ofFloat("scaleX", 1f, 0f, 1f);
PropertyValuesHolder pvhScaleY = PropertyValuesHolder.ofFloat("scaleY", 1f, 0f, 1f);
final ObjectAnimator changeIn = ObjectAnimator.ofPropertyValuesHolder( this, pvhLeft, pvhTop, pvhRight, pvhBottom, pvhScaleX, pvhScaleY).
        setDuration(mTransitioner.getDuration(LayoutTransition.CHANGE_APPEARING));
mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING, changeIn);
changeIn.addListener(new AnimatorListenerAdapter() {
    public void onAnimationEnd(Animator anim) {
        View view = (View) ((ObjectAnimator) anim).getTarget();
        view.setScaleX(1f);
        view.setScaleY(1f);
    }
});

LayoutTransition.CHANGE_DISAPPEARING得使用如下方法。

//Changing while Removing
Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
Keyframe kf1 = Keyframe.ofFloat(.9999f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
final ObjectAnimator changeOut = ObjectAnimator.ofPropertyValuesHolder(this, pvhLeft, pvhTop, pvhRight, pvhBottom, pvhRotation).
        setDuration(mTransitioner.getDuration(LayoutTransition.CHANGE_DISAPPEARING));
mTransitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, changeOut);
changeOut.addListener(new AnimatorListenerAdapter() {
    public void onAnimationEnd(Animator anim) {
        View view = (View) ((ObjectAnimator) anim).getTarget();
        view.setRotation(0f);
    }
});

题外话

在我们的Android模拟器中,往往存在着一个ApiDemos的App,这个App里面分类别演示了很多功能,源码在SDK的安装目录下\sdk\samples\任意一个版本的SDK下,通过这些官方提供的文档,我们可以很清楚的知道具体的实现过程。

Demo下载 : 360云盘  访问密码 3b8f

发表评论

您的电子邮箱地址不会被公开。