Android 漂浮類動效的分析與實現!

來源:互聯網
上載者:User

標籤:android動效   漂浮效果   浮動星空   絢麗動效   canvas.drawbitmap   


尊重原創,歡迎轉載,轉載請註明: FROM  GA_studio   http://blog.csdn.net/tianjian4592  


註:因部分原因,本篇主要講解動效分析的思路,不提供源碼下載,請見諒 ... ...

上一篇只講了Canvas中的drawBitmap方法,並且還說的這個方法好像很膩害、能做出很多牛逼效果的樣子,接下來這篇文章只是為了作為上一篇文章的一個小栗子,進一步拓展大家利用drawBitmap 完成動效的思路!

好了,先上失真的不能再失真的:




咱們先一起來分析下上面的效果:

假定這是你剛從UE 或動效射雞濕手裡拿到上面的動效設計圖,映入眼簾的是蒼茫的星空,漂浮的星球營造出的深邃、浩瀚的宇宙,好了,不多BB了,針對你會想到什麼樣的實現方案?

1. 有些同學可能會想到建立對應數量個ImageView,然後針對每一個ImageView使用 Animation或Animator 去做對應的移動效果;

2.採用自己繪製的方式進行實現,不就是漂浮的星球嗎,咱都給畫出來;


不用說,上面第二種方案肯定更可取,第一種方案有以下幾個缺陷:

1. 建立的view 個數過多,效能太差;

2. 靈活性太差,比如UE或產品要增加或減少星球數量,都會是個麻煩事兒;

3. 對每一個view做移動動畫,開銷太大還不太可控或修改;

針對於此,咱們堅定不移的走自己繪製完成漂浮動效的路線;

既然要繪製,那首先得拿到星球的位元影像,根據星球的種類拿到所有的位元影像:

    /**     * init bitmap info     */    private void initBitmapInfo() {        mBackBitmap = ((BitmapDrawable) mResources.getDrawable(R.drawable.back))                .getBitmap();        mBackWidth = mBackBitmap.getWidth();        mBackHeight = mBackBitmap.getHeight();        mStarOne = ((BitmapDrawable) mResources.getDrawable(R.drawable.star2))                .getBitmap();        mStarOneWidth = mStarOne.getWidth();        mStarOneHeight = mStarOne.getHeight();        mStarTwo = ((BitmapDrawable) mResources.getDrawable(R.drawable.star1))                .getBitmap();        mStarTwoWidth = mStarTwo.getWidth();        mStarTwoHeight = mStarTwo.getHeight();        mStarThree = ((BitmapDrawable) mResources.getDrawable(R.drawable.star3))                .getBitmap();        mStarThreeWidth = mStarThree.getWidth();        mStarThreeHeight = mStarThree.getHeight();    }

上面拿到了背景和三種類型星球的位元影像,根據上面的效果,我們來分析下,有哪些特徵性資料:

1. 同一種星球有大有小;

2. 彼此之間有透明度的差別;

3. 漂浮的方向不一樣;

4. 漂浮的速度不一樣;

5. 每個星球都得有自己的位置;

我們暫且只分析這麼多,基於此,我們抽象出星球對象:

    /**     * 星球     * @author AJian     */    private class StarInfo {        // 縮放比例        float sizePercent;        // x位置        int xLocation;        // y位置        int yLocation;        // 透明度        float alpha;        // 漂浮方向        int direction;        // 漂浮速度        int speed;    }

為了得到上面的部分資料,我們先寫一些資料或方法:

1. 為了初始化星球的位置,我們用數組先定義一批星球的位置(基於view寬高的比例),當然大家也可以隨機,只是隨機可能出現紮堆情況:

private static final float[][] STAR_LOCATION = new float[][] {            {0.5f, 0.2f}, {0.68f, 0.35f}, {0.5f, 0.05f},            {0.15f, 0.15f}, {0.5f, 0.5f}, {0.15f, 0.8f},            {0.2f, 0.3f}, {0.77f, 0.4f}, {0.75f, 0.5f},            {0.8f, 0.55f}, {0.9f, 0.6f}, {0.1f, 0.7f},            {0.1f, 0.1f}, {0.7f, 0.8f}, {0.5f, 0.6f}    };

2. 擷取星球大小的方法(基於原始Bitmap縮放比例):

    /**     * 擷取星球大小     */    private float getStarSize(float start, float end) {        float nextFloat = (float) Math.random();        if (start < nextFloat && nextFloat < end) {            return nextFloat;        } else {            // 如果不處於想要的資料區段,則再隨機一次,因為不斷遞迴有風險            return (float) Math.random();        }    }

3. 定義三種不同快慢的漂浮速度:

        mFloatTransLowSpeed = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 0.5f,                mResources.getDisplayMetrics());        mFloatTransMidSpeed = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 0.75f,                mResources.getDisplayMetrics());        mFloatTransFastSpeed = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1f,                mResources.getDisplayMetrics());

4. 擷取星球漂浮方向的方法:

    /**     * 初始化星球運行方向     */    private int getStarDirection() {        Random random = new Random();        int randomInt = random.nextInt(4);        int direction = 0;        switch (randomInt) {            case 0:                direction = LEFT;                break;            case 1:                direction = RIGHT;                break;            case 2:                direction = TOP;                break;            case 3:                direction = BOTTOM;                break;            default:                break;        }        return direction;    }

有了上面的資料和方法,我們首先初始化一定數量的星球資料:

    /**     * 初始化星球資訊     */    private void initStarInfo() {        StarInfo starInfo = null;        Random random = new Random();        for (int i = 0; i < mStarCount; i++) {            // 擷取星球大小比例            float starSize = getStarSize(0.4f, 0.9f);            // 初始化星球大小            float[] starLocation = STAR_LOCATION[i];            starInfo = new StarInfo();            starInfo.sizePercent = starSize;            // 初始化漂浮速度            int randomSpeed = random.nextInt(3);            switch (randomSpeed) {                case 0:                    starInfo.speed = mFloatTransLowSpeed;                    break;                case 1:                    starInfo.speed = mFloatTransMidSpeed;                    break;                case 2:                    starInfo.speed = mFloatTransFastSpeed;                    break;                default:                    starInfo.speed = mFloatTransMidSpeed;                    break;            }            // 初始化星球透明度            starInfo.alpha = getStarSize(0.3f, 0.8f);            // 初始化星球位置            starInfo.xLocation = (int) (starLocation[0] * mTotalWidth);            starInfo.yLocation = (int) (starLocation[1] * mTotalHeight);            log("xLocation = " + starInfo.xLocation + "--yLocation = "                    + starInfo.yLocation);            log("stoneSize = " + starSize + "---stoneAlpha = "                    + starInfo.alpha);            // 初始化星球位置            starInfo.direction = getStarDirection();            mStarInfos.add(starInfo);        }    }

有了這些資料,我們已經可以將星球繪製在螢幕上:

 private void drawStarDynamic(int count, StarInfo starInfo,            Canvas canvas, Paint paint) {        float starAlpha = starInfo.alpha;        int xLocation = starInfo.xLocation;        int yLocation = starInfo.yLocation;        float sizePercent = starInfo.sizePercent;        xLocation = (int) (xLocation / sizePercent);        yLocation = (int) (yLocation / sizePercent);        Bitmap bitmap = null;        Rect srcRect = null;        Rect destRect = new Rect();        if (count % 3 == 0) {            bitmap = mStarOne;            srcRect = mStarOneSrcRect;            destRect.set(xLocation, yLocation,                    xLocation + mStarOneWidth, yLocation                            + mStarOneHeight);        } else if (count % 2 == 0) {            bitmap = mStarThree;            srcRect = mStarThreeSrcRect;            destRect.set(xLocation, yLocation, xLocation                    + mStarThreeWidth, yLocation + mStarThreeHeight);        } else {            bitmap = mStarTwo;            srcRect = mStarTwoSrcRect;            destRect.set(xLocation, yLocation, xLocation                    + mStarTwoWidth, yLocation + mStarTwoHeight);        }        paint.setAlpha((int) (starAlpha * 255));        canvas.save();        canvas.scale(sizePercent, sizePercent);        canvas.drawBitmap(bitmap, srcRect, destRect, paint);        canvas.restore();    }

接下來要考慮的只是如何讓星球動起來,有了以上資料和思路,相信大家讓星球動起來就不是難事了,只需要根據星球運動的方向,每次重繪的時候將星球的x、y增加或減小對應大小即可:

private void resetStarFloat(StarInfo starInfo) {        switch (starInfo.direction) {            case LEFT:                starInfo.xLocation -= starInfo.speed;                break;            case RIGHT:                starInfo.xLocation += starInfo.speed;                break;            case TOP:                starInfo.yLocation -= starInfo.speed;                break;            case BOTTOM:                starInfo.yLocation += starInfo.speed;                break;            default:                break;        }    }

這時候有部分同學可能會說了,尼瑪, 星球直接移出螢幕了怎麼辦,這個問題相信大家都能解決,只是一個值的判斷和重新修複,不再多言;

最後針對這一類動效小談一下,其實很大一部分效果和上面的動效是類似的,不信?我舉幾個栗子:

1. 雪花飄落的效果

尼瑪,扯淡呢!雪花和這類似?雪花從上往下飛,並且還旋轉;

針對於此,我們只需要在抽取對象的時候加上旋轉角度和旋轉速度(對於旋轉有問題的話,可以參考一個絢麗的loading動效分析與實現!),至於從上往下飛的問題,我們只需要修改x、y的更新策略即可;

2. 很多案頭類應用的花瓣飄落、落英繽紛效果;

基本都是採用以上的分析和實現原理,重要的是對於資料的抽取和靈活運用,其他的也就是根據具體的需求動態更新需要更新的資料,比如位置、大小、透明度等等;


所以,從上面來看,這一類效果其實並不複雜,我們所需要做的只是將複雜動效進行分解、抽取,然後找到每一個小點最適合的實現方式,大的動效化小,然後逐個擊破;

我在寫的過程中會儘可能的把思路描述清楚,因為在我看來,做動效,最主要的還是在於效果的拆解、銜接、解決的思路,思路清晰了,解決方案一般也就明了了;








Android 漂浮類動效的分析與實現!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.