Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 3D旋轉動畫效果

Android 3D旋轉動畫效果

編輯:關於Android編程

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

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

1,自定義旋轉動畫

2,動畫做完後,重置ImageView

 


先看一下程序的運行效果:

 

\

1,自定義動畫類


這裡實現了一個Rotate3dAnimation的類,它擴展了Animation類,重寫applyTransformation()方法,提供指定時間的矩陣變換,我們在這個方法裡,就可以利用Camera類得得到一個圍繞Y軸旋轉的matrix,把這個matrix設置到Transformation對象中。  具體的實現代碼如下:


[java]  @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); 

@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隱藏或顯示。

動畫的listener實現如下:

 


[java]  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 DisplayNextView implements Animation.AnimationListener {

        public void onAnimationStart(Animation animation) {
        }

        public void onAnimationEnd(Animation animation) {

            mContainer.post(new SwapViews());
        }

        public void onAnimationRepeat(Animation animation) {
        }
    }

動畫做完後,執行的代碼如下:

 

[java]  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); 
        } 
    } 

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);
        }
    }

點擊Button的事件處理實現:

 

[java]  @Override 
public void onClick(View v) 

    mCenterX = mContainer.getWidth() / 2; 
    mCenterY = mContainer.getHeight() / 2; 
 
    getDepthZ(); 
 
    applyRotation(mStartAnimView, 0, 90); 

            @Override
            public void onClick(View v)
            {
                mCenterX = mContainer.getWidth() / 2;
                mCenterY = mContainer.getHeight() / 2;

                getDepthZ();

                applyRotation(mStartAnimView, 0, 90);
            }

applyRotation的實現如下:

 


[java]  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); 
    } 

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);
    }

 

3,完整代碼如下


Rotate3dAnimActivity.java


[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); 
        } 
    } 

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
[html]  <?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> 

<?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


[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); 
    } 

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);
    }
}
各位,請想一想,為實現applyTransformation方法時,最後的為什麼要有這兩句話:


        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved