Animation入门

基础

        官方文档

        在安卓中,动画的实现原理很简单。就是通过父View不断调整子View的位置,并且不断地绘制子View。从而形成了一个动画。

帧动画

        使用到的api是AnimationDrawable,其实质是一个Drawable(AnimationDrawable继承于Drawable)

使用步骤:

        1,在res/drawable建立xml文件,用于定义要播放的图片和图片显示的时间。如frame_anim.xml:

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true">
    <item android:drawable="@drawable/rocket_thrust1" android:duration="200" />
    <item android:drawable="@drawable/rocket_thrust2" android:duration="200" />
    <item android:drawable="@drawable/rocket_thrust3" android:duration="200" />
</animation-list>

onShot属性:如果为true,就代表动画不会循环播放;为false代表循环播放

        2,用一个ImageView来显示动画。imageview通过调用setBackgroundResource()来关联相应的动画:

iv = (ImageView) findViewById(R.id.iv_after);
		iv.setBackgroundResource(R.drawable.frame_anim);
        3,开始播放动画
@Override
	public void onWindowFocusChanged(boolean hasFocus) {
		rocketAnimation = (AnimationDrawable) iv.getBackground();
		rocketAnimation.start();
		super.onWindowFocusChanged(hasFocus);
	}
        说明:重写activity的onWindowFocusChanged方法,并在该方法中开始播放动画。这样一来,界面显示的时候就会开始播放该动画。不能在onCreate()中调用start()的方法,因为iv.getBackground()是一个异步方法,可能没有执行完毕就调用了start()方法,这样就无法播放。

        如果无法播放,就需要把帧动画的每一个图片放到res/drawable目录下。

Tween动画(补间动画)

        只需要定义开始帧,结束帧以及持续时间,系统会自动计算出应该补入多少帧,并补入相应的图形,从而完成整个动画。也就是说它的实质上仍是帧动画,不过不需要用户设置太多的静态图片。

Animation

        下面的AlphaAnimation,ScaleAnimation,RotateAnimation,TranslateAnimation及AnimationSet都是继承于Animation。是帧动画的总父类。

        getTransformation:获取帧动画执行到目前时的变换信息。并将信息封装到第二个参数中。一般使用如下:

            Animation anim = mAnimation;
            if (anim != null) {
                anim.getTransformation(
                                    AnimationUtils.currentAnimationTimeMillis(),
                                    mTransformation);
                System.out.println("millis = "+mTransformation.getMatrix());
            }
可以通过Transformation#getMatrix()获取帧动画变换的矩阵,进而使用到Canvas中。

在xml文件中定义

        xml文件是定义在res/anim目录下的。在代码中是通过R.anim.name来引用的,在xml中是通过@anim/name来引用。xml的根结点必须是<set>,<alpha>,<scale>,<translate>,<rotate>五个中的一个。

步骤:

        1,在xml文件定义好动画,

        2,在代码中使用AnimationUtils.loadAnimation()来加载动画,

        3,用组件调用startAnimation()来开始动画

alpha

        透明,对应的类是AlphaAnimation。

        android:fillAfter:动画结束后,会保持动画结束后的样子。

        android:fillBefore:动画结束后,保持动画开始时的样子。

xml文件定义:

<?xml version="1.0" encoding="utf-8"?>
<alpha
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromAlpha="1"
    android:toAlpha="0.1"
    android:duration="1000"
    android:repeatCount="3"
    >
</alpha>
代码中使用动画:
iv = (TextView) findViewById(R.id.iv_after);
		iv.setBackgroundResource(R.drawable.ic_launcher);
		findViewById(R.id.iv_before).setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				AlphaAnimation alphaAnimation = (AlphaAnimation) AnimationUtils
						.loadAnimation(MainActivity.this, R.anim.out);
				iv.startAnimation(alphaAnimation);
			}
		});

rotate

        旋转,对应的是RotateAnimation。

        android:pivotX:旋转的中心点。设置为百分比。如:50%表示以自己的横轴中心;如果是50%p,表示以父类的来计算的。

        android:pivotY:同上。

translate

       平移。对应的是TranslateAnimation。

        android:fromXDelta:从x轴的哪个位置开始移动。注意:开始移动的时候会把view的左上角移动到指定的位置处,然后才开始移动。

        android:toXDelta:左上角要移动到的位置。两者的值的设置和上面的pivotY是一样的。

scale

        缩放。具体属性和上面的差不多。

set

        动画组合。里面可以放置任意的上面三种动画。对应的是AnimationSet。

        set单独具有android:shareInterpolator属性,它指的是:是否共享动画插值器。因为set是一个动画的集合,该属性就是用来指明:这些动画是否共享set中的插值器,默认为true。

        上述的五个动画的共同父类是Animation。可以设置setAnimationListener(),在动画结束的时候再执行别的操作。

示例

        下面是一个帧动画对应的Drawable(来源于apidemo中graphics下AnimateDrawables——继承于Drawable)。截其draw方法如下:

    public void draw(Canvas canvas) {
        Drawable dr = getProxy();//获取使用动画的drawable对象
        if (dr != null) {
            int sc = canvas.save();
            Animation anim = mAnimation;
            if (anim != null) {
                anim.getTransformation(
                                    AnimationUtils.currentAnimationTimeMillis(),
                                    mTransformation);
                System.out.println("millis = "+mTransformation.getMatrix());
                canvas.concat(mTransformation.getMatrix());//将变换的矩阵用于当前的canvas
            }
            dr.draw(canvas);//重新绘制,从而形成了动画
            canvas.restoreToCount(sc);
        }
    }

插值器(Interpolator)

        上面的几个动画中,都有一个属性interpolator。动画就是系统不断地计算,不断地移动;这个移动的过程是需要时间的。因此,在移动的过程中就有快慢之分,而这个属性就是用来指出快慢的分布。比如:越来越快,越来越慢,先快后慢,先慢后快等。常用插值值如下图(来源)


上述的几个插值器也可以通过xml文件来修改其中的一些属性。具体如下(来源):

Animation入门_第1张图片

问题

        动画结束后,点击位置不对。

        其原因是:在动画的过程中,移动的并不是view的实际位置,而是它的显示位置。也就是说它的layout()方法中的参数是没有变化的,因此,它的父View还是认为它在原来的位置,而不是在我们看到的位置(也就是显示位置)。那么在点击的时候,父View在对touch事件进行分发传递的过程时,就会判断错误,从而不会形成我们想要的结果。

        解决办法:在动画结束后,将view的实际位置进行移动,移动到它的显示位置上去。这里有三个方法。而且这些方法都是写在AnimationListener中的onAnimationEnd()方法中的。

其一:

        通过view调用setX,setY,setTranslationX与setTranslationY这些方法(前两个和后两个的作用是一样的,只不过传的值不一样)。并把动画结束后view显示位置的坐标传入其中。要注意:这四个方法都是从api11开始的

其二:

        通过view调用layout(),传入的参数也是动画结束后view的显示位置的坐标。要注意:这种方法可以解决一部分点击事件的问题。当整个布局发现变化时(比如弹出软键盘),view会回到它原来的位置(也就是从布局文件中加载进来时它的位置),而不会保持在layout()方法设置的位置。

其三:

       通过LayoutParams移动view实际位置。

示例:

view.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
			
			@Override
			public void onGlobalLayout() {
				System.out.println(view.getTop()+"---------------");
			}
		});
        首先输出的结果是0,并且在调用onAnimationEnd()时,开始输入的结果仍是0(在第一行就进行输出),等到通过params进行设置之后,再输出时,其值已经变成了160。从这可以发现动画并没有移动view在其父view中的实际位置

示例代码:

public void onAnimationEnd(Animation animation) {
				view.clearAnimation();
				// 通过setX来实现
				// view.setX(view.getLeft());
				// view.setY(2*h/10);
				// view.setTranslationX(0);
				// view.setTranslationY(3.0f*h/10);

				// 通过layout来实现

				// view.layout(view.getLeft(), h / 5, view.getRight(), h/5 +
				// view.getHeight());
				
				RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) view
						.getLayoutParams();
				params.topMargin = 2 * h / 10;
				view.setLayoutParams(params);
			}






你可能感兴趣的:(Animation入门)