对应于三维坐标系中的三个方向,Camera提供了三种旋转方法:
package com.feng.androidtest;import android.graphics.Camera;import android.graphics.Matrix;import android.util.Log;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();Log.i("interpolatedTime", interpolatedTime+"");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); }}可以看出, Rotate3dAnimation 总共做了两件事:在构造函数中赋值了旋转动画所需要的参数,以及重写(override)父类Animation中的applyTransformation()方法,下面分类阐述一下:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@android:color/white" > <Buttonandroid:id="@+id/btn_open"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="16dp"android:onClick="onClickView"android:text="打开"android:textColor="@android:color/black"android:textSize="16sp" /> <RelativeLayoutandroid:id="@+id/rl_content"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_below="@id/btn_open"android:layout_marginTop="16dp" android:background="@android:color/black"><ImageView android:id="@+id/iv_logo" android:layout_width="match_parent" android:layout_height="match_parent" android:contentDescription="@null" android:src="@drawable/ic_qrcode"android:scaleType="centerInside"/><TextView android:id="@+id/tv_desc" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="16dp" android:text="脚本之家。" android:textColor="@android:color/white" android:textSize="18sp"android:visibility="gone"/> </RelativeLayout></RelativeLayout>布局中配置了卡牌正面的图片控件,卡牌背面的文本控件,以及他们的parent容器,也就是本文中的旋转动画的执行对象。
package com.feng.androidtest;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.animation.AccelerateInterpolator;import android.view.animation.Animation;import android.view.animation.Animation.AnimationListener;import android.view.animation.DecelerateInterpolator;import android.widget.Button;import android.widget.ImageView;import android.widget.RelativeLayout;import android.widget.TextView;import com.example.androidtest.R;public class MainActivity extends Activity { private RelativeLayout mContentRl; private ImageView mLogoIv; private TextView mDescTv; private Button mOpenBtn; private int centerX; private int centerY; private int depthZ = 400; private int duration = 600; private Rotate3dAnimation openAnimation; private Rotate3dAnimation closeAnimation; private boolean isOpen = false; @Override protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mContentRl = (RelativeLayout) findViewById(R.id.rl_content);mLogoIv = (ImageView) findViewById(R.id.iv_logo);mDescTv = (TextView) findViewById(R.id.tv_desc);mOpenBtn = (Button) findViewById(R.id.btn_open); } /*** 卡牌文本介绍打开效果:注意旋转角度*/ private void initOpenAnim() {//从0到90度,顺时针旋转视图,此时reverse参数为true,达到90度时动画结束时视图变得不可见,openAnimation = new Rotate3dAnimation(0, 90, centerX, centerY, depthZ, true);openAnimation.setDuration(duration);openAnimation.setFillAfter(true);openAnimation.setInterpolator(new AccelerateInterpolator());openAnimation.setAnimationListener(new AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { } @Override public void onAnimationEnd(Animation animation) {mLogoIv.setVisibility(View.GONE);mDescTv.setVisibility(View.VISIBLE);//从270到360度,顺时针旋转视图,此时reverse参数为false,达到360度动画结束时视图变得可见Rotate3dAnimation rotateAnimation = new Rotate3dAnimation(270, 360, centerX, centerY, depthZ, false);rotateAnimation.setDuration(duration);rotateAnimation.setFillAfter(true);rotateAnimation.setInterpolator(new DecelerateInterpolator());mContentRl.startAnimation(rotateAnimation); }}); } /*** 卡牌文本介绍关闭效果:旋转角度与打开时逆行即可*/ private void initCloseAnim() {closeAnimation = new Rotate3dAnimation(360, 270, centerX, centerY, depthZ, true);closeAnimation.setDuration(duration);closeAnimation.setFillAfter(true);closeAnimation.setInterpolator(new AccelerateInterpolator());closeAnimation.setAnimationListener(new AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { } @Override public void onAnimationEnd(Animation animation) {mLogoIv.setVisibility(View.VISIBLE);mDescTv.setVisibility(View.GONE);Rotate3dAnimation rotateAnimation = new Rotate3dAnimation(90, 0, centerX, centerY, depthZ, false);rotateAnimation.setDuration(duration);rotateAnimation.setFillAfter(true);rotateAnimation.setInterpolator(new DecelerateInterpolator());mContentRl.startAnimation(rotateAnimation); }}); } public void onClickView(View v) {//以旋转对象的中心点为旋转中心点,这里主要不要再onCreate方法中获取,因为视图初始绘制时,获取的宽高为0centerX = mContentRl.getWidth()/2; centerY = mContentRl.getHeight()/2; if (openAnimation == null) { initOpenAnim(); initCloseAnim();} //用作判断当前点击事件发生时动画是否正在执行if (openAnimation.hasStarted() && !openAnimation.hasEnded()) { return;}if (closeAnimation.hasStarted() && !closeAnimation.hasEnded()) { return;}//判断动画执行if (isOpen) { mContentRl.startAnimation(closeAnimation);}else { mContentRl.startAnimation(openAnimation);}isOpen = !isOpen;mOpenBtn.setText(isOpen ? "关闭" : "打开"); }}代码中已对核心的地方做了注释解释,主要弄清楚 rotate3dAnimation构造参数中的 fromDegrees和toDegrees、depthZ、reverse参数,同时在动画中设置了速度插播器,如动画的前半程使用加速器 AccelerateInterpolator,后半程使用减速器 DecelerateInterpolator,使动画体验更加人性化。