Android 3D旋轉動畫效果

主要介紹一下如何實現View的3D旋轉效果,實現的主要原理就是圍繞Y軸旋轉,同時在Z軸方面上有一個深刻的縮放。 java

演示的demo主要有如下幾個重點: android

1,自定義旋轉動畫 app

2,動畫作完後,重置ImageView ide

1,自定義動畫類


這裏實現了一個Rotate3dAnimation的類,它擴展了Animation類,重寫applyTransformation()方法,提供指定時間的矩陣變換,咱們在這個方法裏,就能夠利用Camera類得獲得一個圍繞Y軸旋轉的matrix,把這個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);
}



2,如何使用這個動畫類


在Activity中,咱們有兩個大小同樣的ImageView,它們都放在FrameLayout中,這樣他們位置是重疊的,對最上面的ImageView作動畫(旋轉角度從0到90),當動畫作完後,再對後面的ImageView作動畫(旋轉角度從90到180),在這裏,要控制相應的ImageView隱藏或顯示。 post

private final class DisplayNextView implements Animation.AnimationListener {

        public void onAnimationStart(Animation animation) {
        }

        public void onAnimationEnd(Animation animation) {

            mContainer.post(new SwapViews());
        }

        public void onAnimationRepeat(Animation animation) {
        }
    }



動畫作完後,執行的代碼以下:

private final class SwapViews implements Runnable
    {
        @Override
        public void run()
        {
            mImageView1.setVisibility(View.GONE);
            mImageView2.setVisibility(View.GONE);

            mIndex++;
            if (0 == mIndex % 2)
            {
                mStartAnimView = mImageView1;
            }
            else
            {
                mStartAnimView = mImageView2;
            }

            mStartAnimView.setVisibility(View.VISIBLE);
            mStartAnimView.requestFocus();

            Rotate3dAnimation rotation = new Rotate3dAnimation(
                    -90,
                    0,
                    mCenterX,
                    mCenterY, mDepthZ, false);

            rotation.setDuration(mDuration);
            rotation.setFillAfter(true);
            rotation.setInterpolator(new DecelerateInterpolator());
            mStartAnimView.startAnimation(rotation);
        }
    }



3,完整代碼以下

Rotate3dAnimActivity.java

public class Rotate3dAnimActivity extends Activity { ImageView mImageView1 = null; ImageView mImageView2 = null; ImageView mStartAnimView = null; View mContainer = null; int mDuration = 500; float mCenterX = 0.0f; float mCenterY = 0.0f; float mDepthZ = 0.0f; int mIndex = 0; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.rotate_anim); mImageView1 = (ImageView) findViewById(R.id.imageView1); mImageView2 = (ImageView) findViewById(R.id.imageView2); mContainer = findViewById(R.id.container); mStartAnimView = mImageView1; findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mCenterX = mContainer.getWidth() / 2; mCenterY = mContainer.getHeight() / 2; getDepthZ(); applyRotation(mStartAnimView, 0, 90); } }); InputMethodManager imm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(getWindow().getDecorView().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } private void getDepthZ() { EditText editText = (EditText) findViewById(R.id.edit_depthz); String string = editText.getText().toString(); try { mDepthZ = (float)Integer.parseInt(string); //mDepthZ = Math.min(mDepthZ, 300.0f); } catch (Exception e) { e.printStackTrace(); } } private void applyRotation(View animView, float startAngle, float toAngle) { float centerX = mCenterX; float centerY = mCenterY; Rotate3dAnimation rotation = new Rotate3dAnimation( startAngle, toAngle, centerX, centerY, mDepthZ, true); rotation.setDuration(mDuration); rotation.setFillAfter(true); rotation.setInterpolator(new AccelerateInterpolator()); rotation.setAnimationListener(new DisplayNextView()); animView.startAnimation(rotation); } /** * This class listens for the end of the first half of the animation. * It then posts a new action that effectively swaps the views when the container * is rotated 90 degrees and thus invisible. */ private final class DisplayNextView implements Animation.AnimationListener { public void onAnimationStart(Animation animation) { } public void onAnimationEnd(Animation animation) { mContainer.post(new SwapViews()); } public void onAnimationRepeat(Animation animation) { } } private final class SwapViews implements Runnable { @Override public void run() { mImageView1.setVisibility(View.GONE); mImageView2.setVisibility(View.GONE); mIndex++; if (0 == mIndex % 2) { mStartAnimView = mImageView1; } else { mStartAnimView = mImageView2; } mStartAnimView.setVisibility(View.VISIBLE); mStartAnimView.requestFocus(); Rotate3dAnimation rotation = new Rotate3dAnimation( -90, 0, mCenterX, mCenterY, mDepthZ, false); rotation.setDuration(mDuration); rotation.setFillAfter(true); rotation.setInterpolator(new DecelerateInterpolator()); mStartAnimView.startAnimation(rotation); } } } 



rotate_anim.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:text="Do 3d animation" />
    
    <TextView 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20px"
        android:text="Input Depth on Z axis. [0, 300]"
        />
    <EditText 
        android:id="@+id/edit_depthz"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:text="0"/>

    <FrameLayout 
        android:id="@+id/container"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
       <ImageView
        android:id="@+id/imageView1"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_margin="20dp"
        android:src="@drawable/f" />
       
       <ImageView
        android:id="@+id/imageView2"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_margin="20dp"
        android:src="@drawable/s" 
        android:visibility="gone"/>
        
    </FrameLayout>

</LinearLayout>




Rotate3dAnimation.java

package com.nj1s.lib.anim;

import android.graphics.Camera;
import android.graphics.Matrix;
import android.view.animation.Animation;
import android.view.animation.Transformation;

/**
 * An animation that rotates the view on the Y axis between two specified angles.
 * This animation also adds a translation on the Z axis (depth) to improve the effect.
 */
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;

    /**
     * Creates a new 3D rotation on the Y axis. The rotation is defined by its
     * start angle and its end angle. Both angles are in degrees. The rotation
     * is performed around a center point on the 2D space, definied by a pair
     * of X and Y coordinates, called centerX and centerY. When the animation
     * starts, a translation on the Z axis (depth) is performed. The length
     * of the translation can be specified, as well as whether the translation
     * should be reversed in time.
     *
     * @param fromDegrees the start angle of the 3D rotation
     * @param toDegrees the end angle of the 3D rotation
     * @param centerX the X center of the 3D rotation
     * @param centerY the Y center of the 3D rotation
     * @param reverse true if the translation should be reversed, false otherwise
     */
    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);
    }
}
相關文章
相關標籤/搜索