




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
【移動應用開發(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. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025至2030年中國大型混料桶數(shù)據(jù)監(jiān)測研究報告
- 2025年消防設施操作員之消防設備基礎知識能力測試試卷A卷附答案
- 2025年軍隊文職人員招聘之軍隊文職法學題庫練習試卷B卷附答案
- 電動葫蘆考試試題及答案
- 酒店洗滌合同(2篇)
- 餐飲業(yè)服務培訓試卷
- 中學生課外閱讀指南經典情節(jié)讀后感
- 十萬個為什么科學故事讀后感
- 秦文字從大篆到小篆的演變
- 山東省濱州市2024-2025學年高一上學期1月期末生物學試題(含答案)
- 《駱駝祥子》練習-2023年中考一輪復習:名著導讀(學生版)
- 人工智能在審計工作中的應用
- QFD質量功能展開與產品銷售的關系
- 2024年江蘇省普通高中學業(yè)水平測試小高考生物、地理、歷史、政治試卷及答案(綜合版)
- 維修手機屏幕行業(yè)分析
- 學院食堂排油煙管道清洗項目招投標書范本
- 智鼎在線測評的題庫
- 婦女兒童權益保護知識講座
- 《當下的力量》課件
- 17中國大唐集團公司發(fā)電設備檢修管理辦法大唐集團制〔2023〕94號
- 中建CFG樁施工方案
評論
0/150
提交評論