最近看到一段時(shí)間都沒怎么更新文章了衫哥,一直在學(xué)習(xí)iOS相關(guān)內(nèi)容茎刚。偶然間看到一個(gè)碎裂的粒子效果,覺得很有意思撤逢,就查了查膛锭,參考下網(wǎng)上的思路自己擼了個(gè)輪子。
好了笛质,說了這么多泉沾,先看看效果吧~
依慣例捞蚂,先說下行文思路吧妇押,首先我們先簡(jiǎn)單分析下效果,拆分關(guān)注點(diǎn)姓迅,粒子效果是怎么產(chǎn)生的敲霍?我的解決方案就是先獲取當(dāng)前要碎裂的view的緩存視圖,然后根據(jù)圖片獲取各個(gè)坐標(biāo)點(diǎn)的顏色值丁存,在整個(gè)DecorView蓋上一層視圖肩杈,這個(gè)視圖就根據(jù)獲取的顏色值在要碎裂的view的位置來drawCircle
,之后變化圓心和半徑以及透明度從而產(chǎn)生碎裂效果解寝。那么扩然,我們要解決的問題已經(jīng)簡(jiǎn)化為幾個(gè)點(diǎn)了,看怎么一個(gè)一個(gè)將其擊破聋伦。
一夫偶、獲取view的視圖
二、獲取要碎裂的view的位置以及獲取各個(gè)位置的顏色值
三觉增、變化各個(gè)屬性值產(chǎn)生動(dòng)畫碎裂效果
一兵拢、獲取view的視圖
獲取view的視圖也就是要獲取這個(gè)視圖的截圖,有兩種方式可以來做:
1逾礁、可以用Canvas
來獲取Bitmap
public Bitmap getBitmapFromView(View view) {
Bitmap bmp = Bitmap.createBitmap(webView.getWidth(),
webView.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
view.draw(canvas);
return bmp;
}
2说铃、用getDrawingCache
來獲取Bitmap
private static Bitmap getCacheBitmapFromView(View view) {
final boolean drawingCacheEnabled = true;
view.setDrawingCacheEnabled(drawingCacheEnabled);
view.buildDrawingCache(drawingCacheEnabled);
final Bitmap drawingCache = view.getDrawingCache();
Bitmap bitmap;
if (drawingCache != null) {
bitmap = Bitmap.createBitmap(drawingCache);
view.setDrawingCacheEnabled(false);
} else {
bitmap = null;
}
return bitmap;
}
通過這兩種方式都可以獲取這個(gè)視圖的圖片,而為什么我們要獲取這個(gè)視圖的圖片呢,因?yàn)橐鶕?jù)這個(gè)圖片來獲取各個(gè)位置的顏色值腻扇,為之后繪制粒子效果服務(wù)债热。
二、獲取要碎裂的view的位置以及獲取各個(gè)位置的顏色值
獲取view的位置幼苛,之前使用過getGlobalVisibleRect
方法來獲取位置阳柔,但很多時(shí)候并不是很準(zhǔn)確,比如有ActionBar的時(shí)候蚓峦。
Rect rect = new Rect();
view.getGlobalVisibleRect(rect);
之后測(cè)試使用getLocationInWindow
這種方式挺不錯(cuò)舌剂,這個(gè)方法的官方注釋為這樣寫Computes the coordinates of this view in its window.
:
int[] location = new int[2];
view.getLocationInWindow(location);
Rect rect = new Rect(location[0],location[1],location[0]+view.getMeasuredWidth(),location[1]+view.getMeasuredHeight());
在獲取視圖位置之后,我們要獲取各個(gè)位置的顏色值來繪制在這片區(qū)域內(nèi)暑椰,調(diào)用bitmap.getPixel
方法獲取各個(gè)位置的顏色值:
public static Particle[][] generateParticles(Bitmap bitmap, Rect bound) {
int w = bound.width();
int h = bound.height();
int partW_Count = w / Particle.PART_WH;
int partH_Count = h / Particle.PART_WH;
Particle[][] particles = new Particle[partH_Count][partW_Count];
Point point = null;
for (int row = 0; row < partH_Count; row ++) { //行
for (int column = 0; column < partW_Count; column ++) { //列
//取得當(dāng)前粒子所在位置的顏色
int color = bitmap.getPixel(column * Particle.PART_WH, row * Particle.PART_WH);
point = new Point(column, row); //x是列霍转,y是行
particles[row][column] = Particle.generateParticle(color, bound, point);
}
}
return particles;
}
三、變化各個(gè)屬性值產(chǎn)生動(dòng)畫碎裂效果
首先我們要在當(dāng)前視圖上覆蓋一層產(chǎn)生碎裂效果的視圖:
private void attachToActivity(Activity activity) {
ViewGroup rootView = (ViewGroup) activity.getWindow().getDecorView();
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
rootView.addView(this, lp);
}
將我們要繪制粒子動(dòng)畫效果的添加進(jìn)布局視圖中一汽,然后我們就可以開始繪制了避消。
開啟屬性動(dòng)畫,根據(jù)動(dòng)畫流程變化Particle的相關(guān)屬性:
//x值
public float cx;
//y值
public float cy;
//繪制圓的半徑
public float radius;
//顏色
public int color;
//透明度
public float alpha;
在自定義視圖的onDraw
方法召夹,遍歷所有我們保存的粒子Particle
,改變相關(guān)屬性值:
@Override
protected void onDraw(Canvas canvas) {
if (mParticleAnimator !=null)
drawParticle(canvas);
}
public void drawParticle(Canvas canvas) {
//動(dòng)畫結(jié)束停止
if(!mParticleAnimator.isRunning()) {
return;
}
for (Particle[] particle : mParticleAnimator.getParticles()) {
for (Particle p : particle) {
p.update((Float) mParticleAnimator.getAnimatedValue());
mPaint.setColor(p.color);
mPaint.setAlpha((int) (Color.alpha(p.color) * p.alpha));
canvas.drawCircle(p.cx, p.cy, p.radius, mPaint);//
}
}
invalidate();
}
//更新相關(guān)屬性值 主要是隨機(jī)生成x y值以及碎裂大小
public void update(float factor) {
cx = cx + factor * random.nextInt(mBound.width()) * (random.nextFloat() - 0.5f);
cy = cy + factor * (mBound.height()/(random.nextInt(4)+1)) ;
radius = radius - factor * random.nextInt(3);;
if (radius<=0)
radius = 0;
alpha = 1f - factor;
}
OK岩喷,到這里我們就基本實(shí)現(xiàn)了這個(gè)碎裂效果,整體注意點(diǎn)基本就這么多监憎,我把它簡(jiǎn)單封裝了下纱意,使用方式也很簡(jiǎn)單:
final ParticleView particleAnimator = new ParticleView(MainActivity.this,3000);//3000為動(dòng)畫持續(xù)時(shí)間
particleAnimator.setOnAnimationListener(new ParticleView.OnAnimationListener() {
@Override
public void onAnimationStart(View view,Animator animation) {
//動(dòng)畫開始
view.setVisibility(View.INVISIBLE);
}
@Override
public void onAnimationEnd(View view,Animator animation) {
//動(dòng)畫結(jié)束
}
});
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
particleAnimator.boom(v);//開始動(dòng)畫
}
});
github地址:ParticleDismissLayout