1、什么是自定义animation
在android中,系统提供了一些可以直接使用的animation,如TranslateAniamtion、ScaleAnimation、AlphaAnimation及RotateAnimation。这四种动画对应着平移、缩放、渐变及旋转动画。 在开发中,我们只需要定义好animtion对象,便可以在view上调用startAnimation来实现view的动画。
但如果有些动画,不能用这些动画实现该怎么办呢? 如一些曲线类型的动画。
那么,我们可以通过自定义的animation来实现(通过属性动画也可以实现)。
通过查看上面四种动画的源码可以发现,它们均是继承了Animation类。
该类的说明如下:
/**
* Abstraction for an Animation that can be applied to Views, Surfaces, or
* other objects. See the {@link android.view.animation animation package
* description file}.
*/
public abstract class Animation implements Cloneable {
所以我们也可以尝试继承该类,通过覆写相关方法来实现自定义动画。
2、Rotate3DAnimation实例分析
在google提供的apidemo工程中,有一个Rotate3DAnimation类,从名字可以知道是使view产生3D效果的动画。 其中覆写了Animation类的两个重要方法, 代码如下:
@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) {
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) {
camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
} else {
camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
}
camera.rotateY(degrees);
// 将camera的变化矩阵存入matrix,而matrix会填入Transformation中去,最后系统会调用这个matrix
camera.getMatrix(matrix);
camera.restore();
// pre 的含义是 原有矩阵在前,现有运算矩阵放在原矩阵后面。
matrix.preTranslate(-centerX, -centerY);
// 同理,post的含义是 原有矩阵在在后,现有运算矩阵在前。 故这两行代码的含义在矩阵的最前面 平移 centerX
// 与 centerY ,在最后面 平移 - centerX 与 -centerY。 所以这两行代码交换先后也没关系。
matrix.postTranslate(centerX, centerY);
}
其中,initialize方法中传入了当前做动画的view的宽高和当前view的父view的宽高,在这里可以根据需要来做一些初始化的操作。
applyTransformation方法在动画期间会持续回调,interpolatedTime是当前动画的进度,取值为[0-1], Transformation则封装了动画相关的参数。 此例中将 camera 的matrix 设置给 Transformation 实现在某个特定时间的变化。
3、Camera相关知识点
这个camera是 android.graphics 包下的类,而不是指相机硬件。 这个camera相当于是屏幕外的一个眼睛,通过改变这个“眼睛”的角度及方位等,我们就可以看到不同的视图(也即在屏幕上显示不同的图像)。
由于camera涉及3D操作,所以我们有必要先弄清楚camera下的坐标系。 camera视角下的坐标系与普通的屏幕坐标系不同。
在camera视角下,每个view的左上角为坐标原点(即每个view只要左上角的位置不同,那么camera的坐标原点也不同,可以想像成每个view都有一个单独的camera,通过这个camera将物体映射在屏幕上)。
在camera坐标系中,x轴正向为屏幕向右,y轴正向为屏幕向上,z轴正向为垂直屏幕向外(面对屏幕时,朝向自已为正轴)
camera的位置就位于z轴 - 576 像素处(在z轴负半轴的 8 个单位处,每个单位是72像素)。
3.1 Camera常见操作
camera提供了平移、旋转的操作。 可以直接使用系统相关方法。 对于缩放,没有函数直接支持,但是可以通过平移或修改camera的位置来实现。
在使用旋转操作时,需要注意的是旋转的正负方向。
如果绕 x 轴旋转的话,正向为 屏幕里向屏幕外的方向(面对手机,朝自已的方向为正向)
如果绕 y 轴旋转的话,正向为 屏幕里向屏幕外的方向(面对手机,朝自已的方向为正向),同 x 轴。
如果绕 z 轴旋转的话,正向为顺时针方向。
弄清楚了旋转的方向,才能更好的设置旋转的角度,动画才会按照预想的运行。
除了平移操作,系统提供了设置camera位置的方法,签名如下:
/**
* Sets the location of the camera. The default location is set at
* 0, 0, -8.
*
* @param x The x location of the camera
* @param y The y location of the camera
* @param z The z location of the camera
*/
public native void setLocation(float x, float y, float z);
从注释上可以看到,默认值为-8。 这里的 -8 相当于是负方向的8个单位。一个单位是72像素。 故上面说相机的位置在z轴-576像素处。
通过操作camera,就可以形成不同的视图效果。 但是如何将这种视图效果显示出来? camera提供了两种方法,如下:
1、mCamera.getMatrix(matrix);
2、mCamera.applyToCanvas(canvas);
在Rotate3DAnimation中使用的是方法1,由于其没有canvas,故将变化的matrix取出,然后按照matrix做动画。 在其他自定义view中则可以尝试使用方法2来实现相关效果。
4、Matrix相关知识点
在操作matrix时一定要搞清楚pre与post的区别。 之前老是记错,一段时间不用就理解反了。 这里正解的记法是,pre是将原矩阵放在前,pre操作的参数矩阵在后。而post正好相反,post是将原矩阵放在后,post操作的参数矩阵在前。
matrix类除了提供了常见的操作,如平移、旋转、缩放外还提供了一些较高级的用法。
1、错切。
2、setSinCos 主要用于旋转,相当于设置矩阵中的旋转位置的值。
3、mapPoints(float[] pts), 将输入的点按照当前矩阵进行变化,并将结果存入参数中。
4、setPolyToPoly()方法,参数中通过数组定义了两个多边形,该方法是计算从一个多边形变成另一个多边形所需的矩阵。
其他的方法较多,可以参考文档,这里仅列举一下常用的函数。以备平时开发查阅。
5、自定义animation实例
有了上面的基础知识后,便可以自定义一个动画出来。 这里尝试自定义一个抛物线动画。 关键代码如下:
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
mCamera = new Camera();
mCenterX = width >> 1;
mCenterY = height >> 1;
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
// x 方向上匀速
float x = X_DIS * interpolatedTime;
// y 方向上加速, 为了动画效果,在y上乘以10000
float y = 1.f / 2 * interpolatedTime * interpolatedTime * 10000;
Matrix m = t.getMatrix();
mCamera.save();
// 注意方向,y轴向上是正方向。
mCamera.translate(x, -y, 0);
mCamera.getMatrix(m);
mCamera.restore();
m.preTranslate(-mCenterX, -mCenterY);
m.postTranslate(mCenterX, mCenterY);
}
上面的抛物线没有经过精细的计算,只是为了动画效果随意设置的参数值。 从这个实例可以引申思考一下,对于一些非常规的动画可以尝试使用自定义动画来实现, 如各种曲线类型的动画等。
6、总结
1、自定义动画同普通的视图动画一样,只需在动画时传入动画对象即可。
2、使用Camera时注意其坐标系方向,该方向与view的方向有所区别。
3、matrix的pre操作与post操作均是相对于原矩阵而言的,pre即将原矩阵放在前操作,post亦然。