实现3D旋转效果的方法
Android中有一种旋转效果,是将一个图片进行360度的旋转。
Matrix的作用是对平面上的View进行缩放、平移、旋转,每一种操作都配了setXXX、preXXX、postXXX三个函数。
Camera不是物理摄像头,是android.graphic下的一个类,相当于手机的屏幕,他的坐标系是带有Z坐标的。
可以完成对指定View的X,Y,Z轴的变化,所以可以用来完成3D效果。但是变化之后并不是直接作用于View,而是修改View的Matrix的值,最终View再根据Matrix的值来变换。
Android APIDemos中已经提供了一种例子
1 /** 2 * An animation that rotates the view on the Y axis between two specified angles. 3 * This animation also adds a translation on the Z axis (depth) to improve the effect. 4 */ 5 public class Rotate3dAnimation extends Animation { 6 private final float mFromDegrees; 7 private final float mToDegrees; 8 private final float mCenterX; 9 private final float mCenterY; 10 private final float mDepthZ; 11 private final boolean mReverse; 12 private Camera mCamera; 13 14 /** 15 * Creates a new 3D rotation on the Y axis. The rotation is defined by its 16 * start angle and its end angle. Both angles are in degrees. The rotation 17 * is performed around a center point on the 2D space, definied by a pair 18 * of X and Y coordinates, called centerX and centerY. When the animation 19 * starts, a translation on the Z axis (depth) is performed. The length 20 * of the translation can be specified, as well as whether the translation 21 * should be reversed in time. 22 * 23 * @param fromDegrees the start angle of the 3D rotation 24 * @param toDegrees the end angle of the 3D rotation 25 * @param centerX the X center of the 3D rotation 26 * @param centerY the Y center of the 3D rotation 27 * @param reverse true if the translation should be reversed, false otherwise 28 */ 29 public Rotate3dAnimation(float fromDegrees, float toDegrees, 30 float centerX, float centerY, float depthZ, boolean reverse) { 31 mFromDegrees = fromDegrees; 32 mToDegrees = toDegrees; 33 mCenterX = centerX; 34 mCenterY = centerY; 35 mDepthZ = depthZ; 36 mReverse = reverse; 37 } 38 39 @Override 40 public void initialize(int width, int height, int parentWidth, int parentHeight) { 41 super.initialize(width, height, parentWidth, parentHeight); 42 mCamera = new Camera(); 43 } 44 45 @Override 46 protected void applyTransformation(float interpolatedTime, Transformation t) { 47 final float fromDegrees = mFromDegrees; 48 float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime); 49 50 final float centerX = mCenterX; 51 final float centerY = mCenterY; 52 final Camera camera = mCamera; 53 54 final Matrix matrix = t.getMatrix(); 55 56 camera.save(); 57 if (mReverse) { 58 camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime); 59 } else { 60 camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime)); 61 } 62 camera.rotateY(degrees); 63 camera.getMatrix(matrix); 64 camera.restore(); 65 66 matrix.preTranslate(-centerX, -centerY); 67 matrix.postTranslate(centerX, centerY); 68 } 69 }
如果不需要做特别的效果的话,可以直接照搬
1 import android.graphics.Camera; 2 import android.graphics.Matrix; 3 import android.view.animation.Animation; 4 import android.view.animation.Transformation; 5 6 /** 7 * @author Administrator 8 * 9 */ 10 public class Rotate3DAnimation extends Animation { 11 // 开始角度 12 private final float mFromDegrees; 13 // 结束角度 14 private final float mToDegrees; 15 // 中心点 16 private final float mCenterX; 17 private final float mCenterY; 18 private final float mDepthZ; 19 // 是否需要扭曲 ,也就是是否有Z轴方向深度的变化 20 private final boolean mReverse; 21 // 摄像头 22 private Camera mCamera; 23 public Rotate3DAnimation(float fromDegrees, float toDegrees, float centerX, 24 float centerY, float depthZ, boolean reverse) { 25 mFromDegrees = fromDegrees; 26 mToDegrees = toDegrees; 27 mCenterX = centerX; 28 mCenterY = centerY; 29 mDepthZ = depthZ; 30 mReverse = reverse; 31 } 32 @Override 33 public void initialize(int width, int height, int parentWidth, 34 int parentHeight) { 35 super.initialize(width, height, parentWidth, parentHeight); 36 mCamera = new Camera(); 37 } 38 39 /** 40 * 生成Transformation,整个动画的过程中会不停的被调用 41 * @param interpolatedTime 会逐渐从0增大到1 42 * @param Transformation 变换对象 43 */ 44 @Override 45 protected void applyTransformation(float interpolatedTime, Transformation t) { 46 /** 47 * 实际上整个过程就是通过Camera计算出要旋转所要修改的Matrix的值 48 * 整个函数结束之后,会根据这个Matrix的值进行变化 49 * 也就是说实际最终变换依据的依然是Matrix的值 50 */ 51 final float fromDegrees = mFromDegrees; 52 //生成每次的角度 53 float degrees = fromDegrees 54 + ((mToDegrees - fromDegrees) * interpolatedTime); 55 final float centerX = mCenterX; 56 final float centerY = mCenterY; 57 final Camera camera = mCamera; 58 final Matrix matrix = t.getMatrix();//获取动画对象的矩阵 59 camera.save();//保存摄像机的状态 60 if (mReverse) { //变化的方向是从小往大变 61 camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime); 62 } 63 //旋转到指定的角度 64 camera.rotateY(degrees); 65 //取得变换后的矩阵,修改Matrix的值 66 camera.getMatrix(matrix); 67 camera.restore();//恢复摄像机的状态 ,每次摄像机变换完后,下次又从摄像机初始位置开始变化 68 //将变换的中心点设成中心点 69 matrix.preTranslate(-centerX, -centerY); 70 matrix.postTranslate(centerX, centerY); 71 } 72 }
Activity中的代码
1 import org.cxjchen.animation.Rotate3DAnimation; 2 import android.app.Activity; 3 import android.content.Intent; 4 import android.os.Bundle; 5 import android.view.View; 6 import android.view.View.OnClickListener; 7 import android.view.animation.*; 8 import android.widget.ImageView; 9 import android.widget.TextView; 10 11 12 /** 13 * @author Administrator 14 * 15 */ 16 public class Logo_Activity extends Activity { 17 18 private TextView logo_title = null; 19 20 @Override 21 protected void onCreate(Bundle savedInstanceState) { 22 23 super.onCreate(savedInstanceState); 24 setContentView(R.layout.logo_activity); 25 26 logo_title = (TextView)findViewById(R.id.logo_title); 27 logo_title.setOnClickListener(new OnClickListener() { 28 29 @Override 30 public void onClick(View v) { 31 applyRotation(0,360); 32 } 33 }); 34 } 35 36 37 private void applyRotation(float start, float end) { 38 // 计算中心点 39 final float centerX = logo_title.getWidth() / 2.0f; 40 final float centerY = logo_title.getHeight() / 2.0f; 41 final Rotate3DAnimation rotation = new Rotate3DAnimation(start, end, 42 centerX, centerY, 360.0f, false); 43 rotation.setDuration(1000L); 44 //设置变换后是否维持变换状态 45 rotation.setFillAfter(true); 46 rotation.setInterpolator(new AccelerateInterpolator()); 47 // 设置监听 48 rotation.setAnimationListener(new Animation.AnimationListener() { 49 50 @Override 51 public void onAnimationStart(Animation animation) { 52 } 53 54 @Override 55 public void onAnimationRepeat(Animation animation) { 56 57 } 58 59 @Override 60 public void onAnimationEnd(Animation animation) { 61 62 } 63 }); 64 logo_title.startAnimation(rotation); 65 } 66 67 }