翻牌(翻轉)動畫-Rotate3dAnimation的應用
演示圖.gif
一.目的
應專案需求需要製作一個簽到動畫,類似於翻牌.每次點選簽到,下面的卡牌翻轉一圈.
(原始碼放末尾)
需求圖
二.自定義動畫
在Android實現3D效果方法有Open GL ES和Camera.我使用的是Camera.
關於canmara的解讀,參考了部落格 http://www.gcssloop.com/customview/matrix-3d-camera
下面是Rotate3dAnimation的程式碼:
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; float scale = 1;// <------- 畫素密度 /** * 建立一個繞y軸旋轉的3D動畫效果,旋轉過程中具有深度調節,可以指定旋轉中心。 * @param context<------- 新增上下文,為獲取畫素密度準備 * @param fromDegrees 起始時角度 * @param toDegrees結束時角度 * @param centerX旋轉中心x座標 * @param centerY旋轉中心y座標 * @param depthZ最遠到達的z軸座標 * @param reversetrue 表示由從0到depthZ,false相反 */ public Rotate3dAnimation(Context context, float fromDegrees, float toDegrees, float centerX, float centerY, float depthZ, boolean reverse) { mFromDegrees = fromDegrees; mToDegrees = toDegrees; mCenterX = centerX; mCenterY = centerY; mDepthZ = depthZ; mReverse = reverse; // 獲取手機畫素密度 (即dp與px的比例) scale = context.getResources().getDisplayMetrics().density; } @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)); } // 繞y軸旋轉 camera.rotateY(degrees); camera.getMatrix(matrix); camera.restore(); // 修正失真,主要修改 MPERSP_0 和 MPERSP_1 float[] mValues = new float[9]; matrix.getValues(mValues);//獲取數值 mValues[6] = mValues[6]/scale;//數值修正 mValues[7] = mValues[7]/scale;//數值修正 matrix.setValues(mValues);//重新賦值 // 調節中心點 matrix.preTranslate(-centerX, -centerY); matrix.postTranslate(centerX, centerY); } }
三.使用
這部分的程式碼相對簡單,主要就是為卡牌加上點選事件,點選時執行分步動畫.
注意
1.第一段動畫:卡牌旋轉90度.旋轉至看不見牌面的角度時--即動畫結束時加入監聽.此時將卡牌的畫面變換成你需要的樣子.再執行第二段動畫
2.第二段動畫:讓卡牌從270度旋轉到360度.為什麼不是90到180,是因為轉過去後卡面變映象了.有疑惑的話可以自己試一下.
3.取卡牌寬高需要用到post方法否則取不到.
4.isDark是我用來判斷正反面的,正面在上旋轉時設定反面,反之亦然.如果是簽到這種只需要旋轉一次的就不需要加這個引數了.
package com.maomao.technology.rotate3ddemo; import android.app.Activity; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.view.animation.AccelerateInterpolator; import android.view.animation.Animation; import android.widget.ImageView; import com.bumptech.glide.Glide; public class MainActivity extends Activity { boolean isDark = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initview(); } private void initview() { final ImageView card = findViewById(R.id.card); card.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //用post方法取card的寬高 card.post(new Runnable() { @Override public void run() { //取card中心點 final float centerX = card.getWidth() / 2f; final float centerY = card.getHeight() / 2f; // 構建3D旋轉動畫物件,旋轉角度為0到90度 final Rotate3dAnimation rotation = new Rotate3dAnimation(MainActivity.this, 0, 90, centerX, centerY, 0f, false); // 動畫持續時間500毫秒 rotation.setDuration(500); // 動畫完成後保持完成的狀態 rotation.setFillAfter(true); rotation.setInterpolator(new AccelerateInterpolator()); card.startAnimation(rotation); //監聽器翻轉到90度的時候 卡面圖片改變 然後將卡牌從270度翻轉到360度剛好轉回來 //這裡注意不是90-180度,因為90-180翻轉過來的圖片是左右相反的映象圖 rotation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { //正反面判斷 if (isDark) { isDark = false; } else { isDark = true; } //點正面切換背面,反之亦然 if (isDark) { Glide.with(MainActivity.this).load(R.drawable.light).into(card); } else { Glide.with(MainActivity.this).load(R.drawable.dark).into(card); } //270度翻轉到360度 final Rotate3dAnimation rotation = new Rotate3dAnimation(MainActivity.this, 270, 360, centerX, centerY, 0f, true); rotation.setDuration(500); // 動畫完成後保持完成的狀態 rotation.setFillAfter(false); card.startAnimation(rotation); } @Override public void onAnimationRepeat(Animation animation) { } }); } }); } }); } }