最近接触了动画方面点点滴滴,看到一个关于3D旋转动画方面蛮有趣的小按理,整理出来和大家分享一下。
先来看下效果:
3D效果的实现主要用过Camera,调用camera的rotateX()、rotateY()、rotateZ()方法并传入相应的角度使View能够绕坐标轴旋转,这个按理主要让一个ListView和一个ImageView绕y轴旋转。
首先,通过一个自定义Rotate3dAnimation类扩展之Animation类,并重写它的applyTransformation()方法以及提供指定时间的变换矩阵,通过camera类得到一个依据旋转轴旋转的matrix矩阵并将这个矩阵传入到Transformation对象中去。实现代码如下:
@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.getMatrix(matrix); camera.restore(); matrix.preTranslate(-centerX, -centerY); matrix.postTranslate(centerX, centerY); }
在Activity的布局文件中奖ListView和ImageView放在同一个FrameLayout中,ListView和ImageView位置相互重叠,先后对两个View实现动画效果(ListVIew从0°旋转到90°或者ImageView实现从180°旋转到90°)需要注意一点的是:程序中通过mposition值的大小来判定在旋转后显示或者隐藏的是ListVIew还是ImageView。代码如下:
private final class DisplayNextView implements Animation.AnimationListener { private final int mPosition; private DisplayNextView(int position) { mPosition = position; } public void onAnimationStart(Animation animation) { } public void onAnimationEnd(Animation animation) { mContainer.post(new SwapViews(mPosition)); } public void onAnimationRepeat(Animation animation) { } }
private final class SwapViews implements Runnable { private final int mPosition; public SwapViews(int position) { mPosition = position; } public void run() { final float centerX = mContainer.getWidth() / 2.0f; final float centerY = mContainer.getHeight() / 2.0f; Rotate3dAnimation rotation; if (mPosition > -1) { mPhotosList.setVisibility(View.GONE); mImageView.setVisibility(View.VISIBLE); mImageView.requestFocus(); rotation = new Rotate3dAnimation(90, 180, centerX, centerY, 310.0f, false); } else { mImageView.setVisibility(View.GONE); mPhotosList.setVisibility(View.VISIBLE); mPhotosList.requestFocus(); rotation = new Rotate3dAnimation(90, 0, centerX, centerY, 310.0f, false); } rotation.setDuration(500); rotation.setFillAfter(true); rotation.setInterpolator(new DecelerateInterpolator()); mContainer.startAnimation(rotation); } }另外,分别对listView和ImageView设置监听事件
public void onItemClick(AdapterView<?> parent, View v, int position, long id) { // Pre-load the image then start the animation mImageView.setImageResource(PHOTOS_RESOURCES[position]); applyRotation(position, 0, 90); } public void onClick(View v) { applyRotation(-1, 180, 90); }
private void applyRotation(int position, float start, float end) { // Find the center of the container final float centerX = mContainer.getWidth() / 2.0f; final float centerY = mContainer.getHeight() / 2.0f; // Create a new 3D rotation with the supplied parameter // The animation listener is used to trigger the next animation final Rotate3dAnimation rotation = new Rotate3dAnimation(start, end, centerX, centerY, 310.0f, true); rotation.setDuration(500); rotation.setFillAfter(true); rotation.setInterpolator(new AccelerateInterpolator()); rotation.setAnimationListener(new DisplayNextView(position)); mContainer.startAnimation(rotation); }
public class Rotate3dAnimation extends Animation { private final float mFromDegrees; private final float mToDegrees; private final float mCenterX; private final float mCenterY; private final float mDepthZ; private final boolean mReverse; private Camera mCamera; public Rotate3dAnimation(float fromDegrees, float toDegrees, float centerX, float centerY, float depthZ, boolean reverse) { mFromDegrees = fromDegrees; mToDegrees = toDegrees; mCenterX = centerX; mCenterY = centerY; mDepthZ = depthZ; mReverse = reverse; } @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.getMatrix(matrix); camera.restore(); matrix.preTranslate(-centerX, -centerY); matrix.postTranslate(centerX, centerY); } }