翻牌(翻轉(zhuǎn))動畫-Rotate3dAnimation的應(yīng)用

演示圖.gif

一.目的

應(yīng)項目需求需要制作一個簽到動畫,類似于翻牌.每次點擊簽到,下面的卡牌翻轉(zhuǎn)一圈.
(源碼放末尾)


需求圖

二.自定義動畫

在Android實現(xiàn)3D效果方法有Open GL ES和Camera.我使用的是Camera.

關(guān)于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;    // <------- 像素密度

    /**
     * 創(chuàng)建一個繞y軸旋轉(zhuǎn)的3D動畫效果,旋轉(zhuǎn)過程中具有深度調(diào)節(jié)贮懈,可以指定旋轉(zhuǎn)中心南用。
     * @param context     <------- 添加上下文,為獲取像素密度準(zhǔn)備
     * @param fromDegrees 起始時角度
     * @param toDegrees   結(jié)束時角度
     * @param centerX     旋轉(zhuǎn)中心x坐標(biāo)
     * @param centerY     旋轉(zhuǎn)中心y坐標(biāo)
     * @param depthZ      最遠到達的z軸坐標(biāo)
     * @param reverse     true 表示由從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();

        // 調(diào)節(jié)深度
        if (mReverse) {
            camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
        } else {
            camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
        }

        // 繞y軸旋轉(zhuǎn)
        camera.rotateY(degrees);

        camera.getMatrix(matrix);
        camera.restore();

        // 修正失真彩届,主要修改 MPERSP_0 和 MPERSP_1
        float[] mValues = new float[9];
        matrix.getValues(mValues);              //獲取數(shù)值
        mValues[6] = mValues[6]/scale;          //數(shù)值修正
        mValues[7] = mValues[7]/scale;          //數(shù)值修正
        matrix.setValues(mValues);              //重新賦值

        // 調(diào)節(jié)中心點
        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
    }
}

三.使用

這部分的代碼相對簡單,主要就是為卡牌加上點擊事件,點擊時執(zhí)行分步動畫.

注意

1.第一段動畫:卡牌旋轉(zhuǎn)90度.旋轉(zhuǎn)至看不見牌面的角度時--即動畫結(jié)束時加入監(jiān)聽.此時將卡牌的畫面變換成你需要的樣子.再執(zhí)行第二段動畫
2.第二段動畫:讓卡牌從270度旋轉(zhuǎn)到360度.為什么不是90到180,是因為轉(zhuǎn)過去后卡面變鏡像了.有疑惑的話可以自己試一下.
3.取卡牌寬高需要用到post方法否則取不到.
4.isDark是我用來判斷正反面的,正面在上旋轉(zhuǎn)時設(shè)置反面,反之亦然.如果是簽到這種只需要旋轉(zhuǎn)一次的就不需要加這個參數(shù)了.
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;
                        // 構(gòu)建3D旋轉(zhuǎn)動畫對象,旋轉(zhuǎn)角度為0到90度
                        final Rotate3dAnimation rotation = new Rotate3dAnimation(MainActivity.this, 0, 90, centerX, centerY,
                                0f, false);
                        // 動畫持續(xù)時間500毫秒
                        rotation.setDuration(500);
                        // 動畫完成后保持完成的狀態(tài)
                        rotation.setFillAfter(true);
                        rotation.setInterpolator(new AccelerateInterpolator());
                        card.startAnimation(rotation);
                        //監(jiān)聽器  翻轉(zhuǎn)到90度的時候 卡面圖片改變 然后將卡牌從270度翻轉(zhuǎn)到360度剛好轉(zhuǎn)回來
                        //這里注意不是90-180度,因為90-180翻轉(zhuǎn)過來的圖片是左右相反的鏡像圖
                        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度翻轉(zhuǎn)到360度
                                final Rotate3dAnimation rotation = new Rotate3dAnimation(MainActivity.this, 270, 360, centerX, centerY,
                                        0f, true);
                                rotation.setDuration(500);
                                // 動畫完成后保持完成的狀態(tài)
                                rotation.setFillAfter(false);
                                card.startAnimation(rotation);
                            }

                            @Override
                            public void onAnimationRepeat(Animation animation) {
                            }
                        });

                    }
                });
            }
        });
    }
}

三.源碼

https://github.com/liumaomao0209/Rotate3DDemo

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蔚鸥,更是在濱河造成了極大的恐慌,老刑警劉巖许赃,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件止喷,死亡現(xiàn)場離奇詭異,居然都是意外死亡混聊,警方通過查閱死者的電腦和手機弹谁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來句喜,“玉大人预愤,你說我怎么就攤上這事】任福” “怎么了植康?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長展懈。 經(jīng)常有香客問我销睁,道長,這世上最難降的妖魔是什么存崖? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任冻记,我火速辦了婚禮,結(jié)果婚禮上来惧,老公的妹妹穿的比我還像新娘冗栗。我一直安慰自己,他們只是感情好违寞,可當(dāng)我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布贞瞒。 她就那樣靜靜地躺著,像睡著了一般趁曼。 火紅的嫁衣襯著肌膚如雪军浆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天挡闰,我揣著相機與錄音乒融,去河邊找鬼掰盘。 笑死,一個胖子當(dāng)著我的面吹牛赞季,可吹牛的內(nèi)容都是我干的愧捕。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼申钩,長吁一口氣:“原來是場噩夢啊……” “哼次绘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起撒遣,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤邮偎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后义黎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體禾进,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年廉涕,在試婚紗的時候發(fā)現(xiàn)自己被綠了泻云。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡狐蜕,死狀恐怖宠纯,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情馏鹤,我是刑警寧澤征椒,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站湃累,受9級特大地震影響勃救,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜治力,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一蒙秒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧宵统,春花似錦晕讲、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至痊班,卻和暖如春勤婚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背涤伐。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工馒胆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留缨称,地道東北人。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓祝迂,卻偏偏與公主長得像睦尽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子型雳,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容