在上一篇中我们使用到了位移动画TranslateAnimation,下面我们先来看看TranslateAnimation是如何实现Animation中的抽象方法的:
/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.view.animation; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; /** * An animation that controls the position of an object. See the * {@link android.view.animation full package} description for details and * sample code. * */ public class TranslateAnimation extends Animation { private int mFromXType = ABSOLUTE; private int mToXType = ABSOLUTE; private int mFromYType = ABSOLUTE; private int mToYType = ABSOLUTE; private float mFromXValue = 0.0f; private float mToXValue = 0.0f; private float mFromYValue = 0.0f; private float mToYValue = 0.0f; private float mFromXDelta; private float mToXDelta; private float mFromYDelta; private float mToYDelta; /** * Constructor used when a TranslateAnimation is loaded from a resource. * * @param context Application context to use * @param attrs Attribute set from which to read values */ public TranslateAnimation(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.TranslateAnimation); Description d = Description.parseValue(a.peekValue( com.android.internal.R.styleable.TranslateAnimation_fromXDelta)); mFromXType = d.type; mFromXValue = d.value; d = Description.parseValue(a.peekValue( com.android.internal.R.styleable.TranslateAnimation_toXDelta)); mToXType = d.type; mToXValue = d.value; d = Description.parseValue(a.peekValue( com.android.internal.R.styleable.TranslateAnimation_fromYDelta)); mFromYType = d.type; mFromYValue = d.value; d = Description.parseValue(a.peekValue( com.android.internal.R.styleable.TranslateAnimation_toYDelta)); mToYType = d.type; mToYValue = d.value; a.recycle(); } /** * Constructor to use when building a TranslateAnimation from code * * @param fromXDelta Change in X coordinate to apply at the start of the * animation * @param toXDelta Change in X coordinate to apply at the end of the * animation * @param fromYDelta Change in Y coordinate to apply at the start of the * animation * @param toYDelta Change in Y coordinate to apply at the end of the * animation */ public TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta) { mFromXValue = fromXDelta; mToXValue = toXDelta; mFromYValue = fromYDelta; mToYValue = toYDelta; mFromXType = ABSOLUTE; mToXType = ABSOLUTE; mFromYType = ABSOLUTE; mToYType = ABSOLUTE; } /** * Constructor to use when building a TranslateAnimation from code * * @param fromXType Specifies how fromXValue should be interpreted. One of * Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or * Animation.RELATIVE_TO_PARENT. * @param fromXValue Change in X coordinate to apply at the start of the * animation. This value can either be an absolute number if fromXType * is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise. * @param toXType Specifies how toXValue should be interpreted. One of * Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or * Animation.RELATIVE_TO_PARENT. * @param toXValue Change in X coordinate to apply at the end of the * animation. This value can either be an absolute number if toXType * is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise. * @param fromYType Specifies how fromYValue should be interpreted. One of * Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or * Animation.RELATIVE_TO_PARENT. * @param fromYValue Change in Y coordinate to apply at the start of the * animation. This value can either be an absolute number if fromYType * is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise. * @param toYType Specifies how toYValue should be interpreted. One of * Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or * Animation.RELATIVE_TO_PARENT. * @param toYValue Change in Y coordinate to apply at the end of the * animation. This value can either be an absolute number if toYType * is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise. */ public TranslateAnimation(int fromXType, float fromXValue, int toXType, float toXValue, int fromYType, float fromYValue, int toYType, float toYValue) { mFromXValue = fromXValue; mToXValue = toXValue; mFromYValue = fromYValue; mToYValue = toYValue; mFromXType = fromXType; mToXType = toXType; mFromYType = fromYType; mToYType = toYType; } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { float dx = mFromXDelta; float dy = mFromYDelta; if (mFromXDelta != mToXDelta) { dx = mFromXDelta + ((mToXDelta - mFromXDelta) * interpolatedTime); } if (mFromYDelta != mToYDelta) { dy = mFromYDelta + ((mToYDelta - mFromYDelta) * interpolatedTime); } t.getMatrix().setTranslate(dx, dy); } @Override public void initialize(int width, int height, int parentWidth, int parentHeight) { super.initialize(width, height, parentWidth, parentHeight); mFromXDelta = resolveSize(mFromXType, mFromXValue, width, parentWidth); mToXDelta = resolveSize(mToXType, mToXValue, width, parentWidth); mFromYDelta = resolveSize(mFromYType, mFromYValue, height, parentHeight); mToYDelta = resolveSize(mToYType, mToYValue, height, parentHeight); }可以看到实际上重写了两个方法:initialize和applyTransformation
/** * Initialize this animation with the dimensions of the object being * animated as well as the objects parents. (This is to support animation * sizes being specifed relative to these dimensions.) * * <p>Objects that interpret Animations should call this method when * the sizes of the object being animated and its parent are known, and * before calling {@link #getTransformation}. * * * @param width Width of the object being animated * @param height Height of the object being animated * @param parentWidth Width of the animated object's parent * @param parentHeight Height of the animated object's parent */ public void initialize(int width, int height, int parentWidth, int parentHeight) { reset(); mInitialized = true; }
/** * Helper for getTransformation. Subclasses should implement this to apply * their transforms given an interpolation value. Implementations of this * method should always replace the specified Transformation or document * they are doing otherwise. * * @param interpolatedTime The value of the normalized time (0.0 to 1.0) * after it has been run through the interpolation function. * @param t The Transofrmation object to fill in with the current * transforms. */ protected void applyTransformation(float interpolatedTime, Transformation t) { }从initialize方法的注释上看,这个方法的主要作用是:初始化对象的尺寸以及父容器尺寸(为了确定和父容器的相对位置)。
从applyTransformation方法的注释上看,这个方法应该被实现,这个方法给出了一个interpolation值,并帮助获得Transformation对象,应该自己设置transformation对象来实现自己的动画效果。
好吧,基于以上研究,我们试着来重写一个Animation
package com.example.testanimation; import android.graphics.Camera; import android.graphics.Matrix; import android.view.animation.Animation; import android.view.animation.LinearInterpolator; import android.view.animation.Transformation; /** * 自定义动画 * @author 阳光小强 * */ public class MyAnimation extends Animation{ private float centerX; private float centerY; private int duration; private Camera camera = new Camera(); public MyAnimation(float x, float y, int duration){ this.centerX = x; this.centerY = y; this.duration = duration; } @Override public void initialize(int width, int height, int parentWidth, int parentHeight) { super.initialize(width, height, parentWidth, parentHeight); setDuration(duration); setFillAfter(true); setInterpolator(new LinearInterpolator()); } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { camera.save(); camera.translate(100f - 100f * interpolatedTime, 150f * interpolatedTime -150, 80f - 80f * interpolatedTime); camera.rotateY(360 * interpolatedTime); camera.rotateX(360 * interpolatedTime); Matrix matrix = t.getMatrix(); camera.getMatrix(matrix); matrix.preTranslate(-centerX, -centerY); matrix.postTranslate(centerX, centerY); camera.restore(); } }代码解释:
1、setDuration(duration):设置动画时间
2、setFillAfter(true):设置动画结束后保持,如果设为false则动画结束后回到原来状态。
3、setInterpolator(new LinearInterpolator()):Interpolater实际上是控制补间动画的插入帧的频率的,所以就会有加速、减速、匀速动画。
4、Camera:一个空间变换工具,类似于Matrix,提供了各种变换方法,如上面的translate和rotateY等。
5、Matrix:一个三维的矩阵变换函数。
6、camera.getMatrix(matrix):计算当前的矩阵变换,并将其复制到矩阵matrix中。
7、matrix.preTranslate :执行矩阵指定的转换。
8、matrix.postTranslate:执行矩阵指定的转换(后面两个方法怎么转换,有什么区别,这就是数学知识了,一两句也说不清)。