【移動應用開發(fā)技術】 Android 中 View 炸裂特效的實現(xiàn)分析 IT藍豹_第1頁
【移動應用開發(fā)技術】 Android 中 View 炸裂特效的實現(xiàn)分析 IT藍豹_第2頁
【移動應用開發(fā)技術】 Android 中 View 炸裂特效的實現(xiàn)分析 IT藍豹_第3頁
【移動應用開發(fā)技術】 Android 中 View 炸裂特效的實現(xiàn)分析 IT藍豹_第4頁
【移動應用開發(fā)技術】 Android 中 View 炸裂特效的實現(xiàn)分析 IT藍豹_第5頁
已閱讀5頁,還剩3頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

【移動應用開發(fā)技術】Android中View炸裂特效的實現(xiàn)分析IT藍豹

前幾天微博上被一個很優(yōu)秀的Android開源組件刷屏了-ExplosionField,效果非常酷炫,有點類似MIUI卸載APP時的動畫,先來感受一下。ExplosionField不但效果很拉風,代碼寫得也相當好,讓人忍不住要拿來好好讀一下。創(chuàng)建ExplosionFieldExplosionField繼承自View,在onDraw方法中繪制動畫特效,并且它提供了一個attach3Window方法,可以把ExplosionField最為一個子View添加到Activity上的rootview中。public

static

ExplosionField

attach3Window(Activity

activity)

{

ViewGroup

rootView

=

(ViewGroup)

activity.findViewById(Window.ID_ANDROID_CONTENT);

ExplosionField

explosionField

=

new

ExplosionField(activity);

rootView.addView(explosionField,

new

ViewGroup.LayoutParams(

ViewGroup.LayoutParams.MATCH_PARENT,

ViewGroup.LayoutParams.MATCH_PARENT));

return

explosionField;

}1234567explosionField的LayoutParams屬性都被設置為MATCH_PARENT,這樣一來,一個view炸裂出來的粒子可以繪制在整個Activity所在的區(qū)域。知識點:可以用Window.ID_ANDROID_CONTENT來替代android.R.id.content知識點:可以用Window.ID_ANDROID_CONTENT來替代android.R.id.content炸裂之前的震動效果在View的點擊事件中,調用mExplosionField.explode(v)之后,View首先會震動,然后再炸裂。震動效果比較簡單,設定一個[0,1]區(qū)間ValueAnimator,然后在AnimatorUpdateListener的onAnimationUpdate中隨機平移x和y坐標,最后把scale和alpha值動態(tài)減為0。int

startDelay

=

100;

ValueAnimator

animator

=

ValueAnimator.ofFloat(0f,

1f).setDuration(150);

animator.addUpdateListener(new

ValueAnimator.AnimatorUpdateListener()

{

Random

random

=

new

Random();

@Override

public

void

onAnimationUpdate(ValueAnimator

animation)

{

view.setTranslationX((random.nextFloat()

-

0.5f)

*

view.getWidth()

*

0.05f);

view.setTranslationY((random.nextFloat()

-

0.5f)

*

view.getHeight()

*

0.05f);

}

});

animator.start();

view.animate().setDuration(150).setStartDelay(startDelay).scaleX(0f).scaleY(0f).alpha(0f).start();123456789101112131415根據(jù)View創(chuàng)建一個bitmapView震動完了就開始進行最難的炸裂,并且炸裂是跟隱藏同時進行的,先來看一下炸裂的API-voidexplode(Bitmapbitmap,Rectbound,longstartDelay,longduration):前兩個參數(shù)bitmap和bound是關鍵,通過View來創(chuàng)建bitmap的代碼比較有意思。如果View是一個ImageView,并且它的Drawable是一個BitmapDrawable就可以直接獲取這個Bitmap。if

(view

instanceof

ImageView)

{

Drawable

drawable

=

((ImageView)

view).getDrawable();

if

(drawable

!=

null

&&

drawable

instanceof

BitmapDrawable)

{

return

((BitmapDrawable)

drawable).getBitmap();

}

}123456如果不是一個ImageView,可以按照如下步驟創(chuàng)建一個bitmap:新建一個Canvas根據(jù)View的大小創(chuàng)建一個空的bitmap把空的bitmap設置為Canvas的底布把view繪制在canvas上把canvas的bitmap設置成null當然,繪制之前要清掉View的焦點,因為焦點可能會改變一個View的UI狀態(tài)。一下代碼中用到的sCanvas是一個靜態(tài)變量,這樣可以節(jié)省每次創(chuàng)建時產生的開銷。view.clearFocus();

Bitmap

bitmap

=

createBitmapSafely(view.getWidth(),

view.getHeight(),

Bitmap.Config.ARGB_8888,

1);if

(bitmap

!=

null)

{

synchronized

(sCanvas)

{

Canvas

canvas

=

sCanvas;

canvas.setBitmap(bitmap);

view.draw(canvas);

canvas.setBitmap(null);

}

}1234567891011作者創(chuàng)建位圖的辦法非常巧妙,如果新建Bitmap時產生了OOM,可以主動進行一次GC-System.gc(),然后再次嘗試創(chuàng)建。這個函數(shù)的實現(xiàn)方式讓人佩服作者的功力。public

static

Bitmap

createBitmapSafely(int

width,

int

height,

Bitmap.Config

config,

int

retryCount)

{

try

{

return

Bitmap.createBitmap(width,

height,

config);

}

catch

(OutOfMemoryError

e)

{

e.printStackTrace();

if

(retryCount

>

0)

{

System.gc();

return

createBitmapSafely(width,

height,

config,

retryCount

-

1);

}

return

null;

}

}123456789101112出了bitmap,還有一個一個很重要的參數(shù)bound,它的創(chuàng)建相對比較簡單:Rect

r

=

new

Rect();

view.getGlobalVisibleRect(r);int[]

location

=

new

int[2];

getLocationOnScreen(location);

r.offset(-location[0],

-location[1]);

r.inset(-mExpandInset[0],

-mExpandInset[1]);123456首先獲取需要炸裂的View的全局可視區(qū)域-Rectr,然后通過getLocationOnScreen(location)獲取ExplosionField在屏幕中的坐標,并根據(jù)這個坐標把炸裂View的可視區(qū)域進行平移,這樣炸裂效果才會顯示在ExplosionField中,最后根據(jù)mExpandInset值(默認為0)擴展一下。那創(chuàng)建的bitmap和bound有什么用呢?我們繼續(xù)往下分析。創(chuàng)建粒子先來看一下炸裂成粒子這個方法的全貌:public

void

explode(Bitmap

bitmap,

Rect

bound,

long

startDelay,

long

duration)

{

final

ExplosionAnimator

explosion

=

new

ExplosionAnimator(this,

bitmap,

bound);

explosion.addListener(new

AnimatorListenerAdapter()

{

@Override

public

void

onAnimationEnd(Animator

animation)

{

mExplosions.remove(animation);

}

});

explosion.setStartDelay(startDelay);

explosion.setDuration(duration);

mExplosions.add(explosion);

explosion.start();

}12345678910111213這里要解釋一下為什么用一個容器類變量-mExplosions來保存一個ExplosionAnimator。因為activity中多個View的炸裂效果可能要同時進行,所以要把每個View對應的炸裂動畫保存起來,等動畫結束的時候再刪掉。作者自定義了一個繼承自ValueAnimator的類-ExplosionAnimator,它主要做了兩件事情,一個是創(chuàng)建粒子-generateParticle,另一個是繪制粒子-draw(Canvascanvas)。先來看一下構造函數(shù):public

ExplosionAnimator(View

container,

Bitmap

bitmap,

Rect

bound)

{

mPaint

=

new

Paint();

mBound

=

new

Rect(bound);

int

partLen

=

15;

mParticles

=

new

Particle[partLen

*

partLen];

Random

random

=

new

Random(System.currentTimeMillis());

int

w

=

bitmap.getWidth()

/

(partLen

+

2);

int

h

=

bitmap.getHeight()

/

(partLen

+

2);

for

(int

i

=

0;

i

<

partLen;

i++)

{

for

(int

j

=

0;

j

<

partLen;

j++)

{

mParticles[(i

*

partLen)

+

j]

=

generateParticle(bitmap.getPixel((j

+

1)

*

w,

(i

+

1)

*

h),

random);

}

}

mContainer

=

container;

setFloatValues(0f,

END_VALUE);

setInterpolator(DEFAULT_INTERPOLATOR);

setDuration(DEFAULT_DURATION);

}123456789101112131415161718根據(jù)構造函數(shù)可以知道作者把bitmap分成了一個17x17的矩陣,每個元素的寬度和高度分別是w和h。int

w

=

bitmap.getWidth()

/

(partLen

+

2);int

h

=

bitmap.getHeight()

/

(partLen

+

2);12所有的粒子是一個15x15的矩陣,元素色值是位圖對應的像素值。bitmap.getPixel((j

+

1)

*

w,

(i

+

1)

*

h)1結構如下圖所示,其中空心部分是粒子。

●generateParticle會根據(jù)一定的算法隨機地生成一個粒子。這部分比較繁瑣,分析略去。其中比較巧妙的還是它的draw方法:public

boolean

draw(Canvas

canvas)

{

if

(!isStarted())

{

return

false;

}

for

(Particle

particle

:

mParticles)

{

particle.advance((float)

getAnimatedValue());

if

(particle.alpha

>

0f)

{

mPaint.setColor(particle.color);

mPaint.setAlpha((int)

(Color.alpha(particle.color)

*

particle.alpha));

canvas.drawCircle(particle.cx,

particle.cy,

particle.radius,

mPaint);

}

}

mContainer.invalidate();

return

true;

}123456789101112131415剛開始我還一直比較困惑,既然繪制粒子是在ExplosionField的onDraw方法中進行,那肯定需要不停地刷新,結果作者并不是這么做的,實現(xiàn)方法又著實驚艷了一把。首先,作者在ExplosionAnimator類中重載了start()方法,通過調用mContainer.invalidate(mBound)來刷新將要炸裂的View所對應的區(qū)塊。@Overridepublic

void

start()

{

super.start();

mContainer.invalidate(mBound);

}12345而mContainer即是占滿了activity的view-ExplosionField,它的onDraw方法中又會調用ExplosionAnimator

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論