parent
525b59acda
commit
8171e64a30
@ -0,0 +1,150 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2015 tyrantgit |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
package xyz.fycz.myreader.widget.explosion_field; |
||||||
|
|
||||||
|
import android.animation.ValueAnimator; |
||||||
|
import android.graphics.Bitmap; |
||||||
|
import android.graphics.Canvas; |
||||||
|
import android.graphics.Color; |
||||||
|
import android.graphics.Paint; |
||||||
|
import android.graphics.Rect; |
||||||
|
import android.view.View; |
||||||
|
import android.view.animation.AccelerateInterpolator; |
||||||
|
import android.view.animation.Interpolator; |
||||||
|
|
||||||
|
import java.util.Random; |
||||||
|
|
||||||
|
public class ExplosionAnimator extends ValueAnimator { |
||||||
|
|
||||||
|
static long DEFAULT_DURATION = 0x400; |
||||||
|
private static final Interpolator DEFAULT_INTERPOLATOR = new AccelerateInterpolator(0.6f); |
||||||
|
private static final float END_VALUE = 1.4f; |
||||||
|
private static final float X = Utils.dp2Px(5); |
||||||
|
private static final float Y = Utils.dp2Px(20); |
||||||
|
private static final float V = Utils.dp2Px(2); |
||||||
|
private static final float W = Utils.dp2Px(1); |
||||||
|
private Paint mPaint; |
||||||
|
private Particle[] mParticles; |
||||||
|
private Rect mBound; |
||||||
|
private View mContainer; |
||||||
|
|
||||||
|
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); |
||||||
|
} |
||||||
|
|
||||||
|
private Particle generateParticle(int color, Random random) { |
||||||
|
Particle particle = new Particle(); |
||||||
|
particle.color = color; |
||||||
|
particle.radius = V; |
||||||
|
if (random.nextFloat() < 0.2f) { |
||||||
|
particle.baseRadius = V + ((X - V) * random.nextFloat()); |
||||||
|
} else { |
||||||
|
particle.baseRadius = W + ((V - W) * random.nextFloat()); |
||||||
|
} |
||||||
|
float nextFloat = random.nextFloat(); |
||||||
|
particle.top = mBound.height() * ((0.18f * random.nextFloat()) + 0.2f); |
||||||
|
particle.top = nextFloat < 0.2f ? particle.top : particle.top + ((particle.top * 0.2f) * random.nextFloat()); |
||||||
|
particle.bottom = (mBound.height() * (random.nextFloat() - 0.5f)) * 1.8f; |
||||||
|
float f = nextFloat < 0.2f ? particle.bottom : nextFloat < 0.8f ? particle.bottom * 0.6f : particle.bottom * 0.3f; |
||||||
|
particle.bottom = f; |
||||||
|
particle.mag = 4.0f * particle.top / particle.bottom; |
||||||
|
particle.neg = (-particle.mag) / particle.bottom; |
||||||
|
f = mBound.centerX() + (Y * (random.nextFloat() - 0.5f)); |
||||||
|
particle.baseCx = f; |
||||||
|
particle.cx = f; |
||||||
|
f = mBound.centerY() + (Y * (random.nextFloat() - 0.5f)); |
||||||
|
particle.baseCy = f; |
||||||
|
particle.cy = f; |
||||||
|
particle.life = END_VALUE / 10 * random.nextFloat(); |
||||||
|
particle.overflow = 0.4f * random.nextFloat(); |
||||||
|
particle.alpha = 1f; |
||||||
|
return particle; |
||||||
|
} |
||||||
|
|
||||||
|
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; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void start() { |
||||||
|
super.start(); |
||||||
|
mContainer.invalidate(mBound); |
||||||
|
} |
||||||
|
|
||||||
|
private class Particle { |
||||||
|
float alpha; |
||||||
|
int color; |
||||||
|
float cx; |
||||||
|
float cy; |
||||||
|
float radius; |
||||||
|
float baseCx; |
||||||
|
float baseCy; |
||||||
|
float baseRadius; |
||||||
|
float top; |
||||||
|
float bottom; |
||||||
|
float mag; |
||||||
|
float neg; |
||||||
|
float life; |
||||||
|
float overflow; |
||||||
|
|
||||||
|
|
||||||
|
public void advance(float factor) { |
||||||
|
float f = 0f; |
||||||
|
float normalization = factor / END_VALUE; |
||||||
|
if (normalization < life || normalization > 1f - overflow) { |
||||||
|
alpha = 0f; |
||||||
|
return; |
||||||
|
} |
||||||
|
normalization = (normalization - life) / (1f - life - overflow); |
||||||
|
float f2 = normalization * END_VALUE; |
||||||
|
if (normalization >= 0.7f) { |
||||||
|
f = (normalization - 0.7f) / 0.3f; |
||||||
|
} |
||||||
|
alpha = 1f - f; |
||||||
|
f = bottom * f2; |
||||||
|
cx = baseCx + f; |
||||||
|
cy = (float) (baseCy - this.neg * Math.pow(f, 2.0)) - f * mag; |
||||||
|
radius = V + (baseRadius - V) * f2; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,200 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2015 tyrantgit |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
package xyz.fycz.myreader.widget.explosion_field; |
||||||
|
|
||||||
|
import android.animation.Animator; |
||||||
|
import android.animation.AnimatorListenerAdapter; |
||||||
|
import android.animation.ValueAnimator; |
||||||
|
import android.app.Activity; |
||||||
|
import android.content.Context; |
||||||
|
import android.graphics.Bitmap; |
||||||
|
import android.graphics.Canvas; |
||||||
|
import android.graphics.Rect; |
||||||
|
import android.media.MediaPlayer; |
||||||
|
import android.util.AttributeSet; |
||||||
|
import android.util.Log; |
||||||
|
import android.view.View; |
||||||
|
import android.view.ViewGroup; |
||||||
|
import android.view.Window; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Random; |
||||||
|
|
||||||
|
|
||||||
|
public class ExplosionField extends View { |
||||||
|
|
||||||
|
private long customDuration = ExplosionAnimator.DEFAULT_DURATION; |
||||||
|
private int idPlayAnimationEffect = 0; |
||||||
|
private OnAnimatorListener mZAnimatorListener; |
||||||
|
private OnClickListener mOnClickListener; |
||||||
|
|
||||||
|
private List<ExplosionAnimator> mExplosions = new ArrayList<>(); |
||||||
|
private int[] mExpandInset = new int[2]; |
||||||
|
|
||||||
|
public ExplosionField(Context context) { |
||||||
|
super(context); |
||||||
|
init(); |
||||||
|
} |
||||||
|
|
||||||
|
public ExplosionField(Context context, AttributeSet attrs) { |
||||||
|
super(context, attrs); |
||||||
|
init(); |
||||||
|
} |
||||||
|
|
||||||
|
public ExplosionField(Context context, AttributeSet attrs, int defStyleAttr) { |
||||||
|
super(context, attrs, defStyleAttr); |
||||||
|
init(); |
||||||
|
} |
||||||
|
|
||||||
|
private void init() { |
||||||
|
|
||||||
|
Arrays.fill(mExpandInset, Utils.dp2Px(32)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onDraw(Canvas canvas) { |
||||||
|
super.onDraw(canvas); |
||||||
|
for (ExplosionAnimator explosion : mExplosions) { |
||||||
|
explosion.draw(canvas); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void playSoundAnimationEffect(int id) { |
||||||
|
this.idPlayAnimationEffect = id; |
||||||
|
} |
||||||
|
|
||||||
|
public void setCustomDuration(long customDuration) { |
||||||
|
this.customDuration = customDuration; |
||||||
|
} |
||||||
|
|
||||||
|
public void addActionEvent(OnAnimatorListener ievents) { |
||||||
|
this.mZAnimatorListener = ievents; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void expandExplosionBound(int dx, int dy) { |
||||||
|
mExpandInset[0] = dx; |
||||||
|
mExpandInset[1] = dy; |
||||||
|
} |
||||||
|
|
||||||
|
public void explode(Bitmap bitmap, Rect bound, long startDelay) { |
||||||
|
explode(bitmap, bound, startDelay, null); |
||||||
|
} |
||||||
|
|
||||||
|
public void explode(Bitmap bitmap, Rect bound, long startDelay, final View view) { |
||||||
|
long currentDuration = customDuration; |
||||||
|
final ExplosionAnimator explosion = new ExplosionAnimator(this, bitmap, bound); |
||||||
|
explosion.addListener(new AnimatorListenerAdapter() { |
||||||
|
@Override |
||||||
|
public void onAnimationEnd(Animator animation) { |
||||||
|
mExplosions.remove(animation); |
||||||
|
if (view != null) { |
||||||
|
view.setScaleX(1); |
||||||
|
view.setScaleY(1); |
||||||
|
view.setAlpha(1); |
||||||
|
view.setOnClickListener(mOnClickListener);//set event
|
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
explosion.setStartDelay(startDelay); |
||||||
|
explosion.setDuration(currentDuration); |
||||||
|
mExplosions.add(explosion); |
||||||
|
explosion.start(); |
||||||
|
} |
||||||
|
|
||||||
|
public void explode(View view) { |
||||||
|
explode(view, false); |
||||||
|
} |
||||||
|
|
||||||
|
public void explode(final View view, Boolean restartState) { |
||||||
|
|
||||||
|
Rect r = new Rect(); |
||||||
|
view.getGlobalVisibleRect(r); |
||||||
|
int[] location = new int[2]; |
||||||
|
getLocationOnScreen(location); |
||||||
|
// getLocationInWindow(location);
|
||||||
|
// view.getLocationInWindow(location);
|
||||||
|
r.offset(-location[0], -location[1]); |
||||||
|
r.inset(-mExpandInset[0], -mExpandInset[1]); |
||||||
|
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.addListener(new Animator.AnimatorListener() { |
||||||
|
@Override |
||||||
|
public void onAnimationStart(Animator animator) { |
||||||
|
if (idPlayAnimationEffect != 0) |
||||||
|
MediaPlayer.create(getContext(), idPlayAnimationEffect).start(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onAnimationEnd(Animator animator) { |
||||||
|
if (mZAnimatorListener != null) { |
||||||
|
mZAnimatorListener.onAnimationEnd(animator, ExplosionField.this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onAnimationCancel(Animator animator) { |
||||||
|
Log.i("PRUEBA", "CANCEL"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onAnimationRepeat(Animator animator) { |
||||||
|
Log.i("PRUEBA", "REPEAT"); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
animator.start(); |
||||||
|
view.animate().setDuration(150).setStartDelay(startDelay).scaleX(0f).scaleY(0f).alpha(0f).start(); |
||||||
|
if (restartState) |
||||||
|
explode(Utils.createBitmapFromView(view), r, startDelay, view); |
||||||
|
else |
||||||
|
explode(Utils.createBitmapFromView(view), r, startDelay); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void clear() { |
||||||
|
mExplosions.clear(); |
||||||
|
invalidate(); |
||||||
|
} |
||||||
|
|
||||||
|
public static ExplosionField attach2Window(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; |
||||||
|
} |
||||||
|
|
||||||
|
public void setOnClickListener(OnClickListener mOnClickListener) { |
||||||
|
this.mOnClickListener = mOnClickListener; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,8 @@ |
|||||||
|
package xyz.fycz.myreader.widget.explosion_field; |
||||||
|
|
||||||
|
import android.animation.Animator; |
||||||
|
import android.view.View; |
||||||
|
|
||||||
|
public interface OnAnimatorListener { |
||||||
|
void onAnimationEnd(Animator animator, View view); |
||||||
|
} |
@ -0,0 +1,72 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2015 tyrantgit |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
package xyz.fycz.myreader.widget.explosion_field; |
||||||
|
|
||||||
|
|
||||||
|
import android.content.res.Resources; |
||||||
|
import android.graphics.Bitmap; |
||||||
|
import android.graphics.Canvas; |
||||||
|
import android.graphics.drawable.BitmapDrawable; |
||||||
|
import android.graphics.drawable.Drawable; |
||||||
|
import android.view.View; |
||||||
|
import android.widget.ImageView; |
||||||
|
|
||||||
|
public class Utils { |
||||||
|
|
||||||
|
private Utils() { |
||||||
|
} |
||||||
|
|
||||||
|
private static final float DENSITY = Resources.getSystem().getDisplayMetrics().density; |
||||||
|
private static final Canvas sCanvas = new Canvas(); |
||||||
|
|
||||||
|
public static int dp2Px(int dp) { |
||||||
|
return Math.round(dp * DENSITY); |
||||||
|
} |
||||||
|
|
||||||
|
public static Bitmap createBitmapFromView(View view) { |
||||||
|
if (view instanceof ImageView) { |
||||||
|
Drawable drawable = ((ImageView) view).getDrawable(); |
||||||
|
if (drawable != null && drawable instanceof BitmapDrawable) { |
||||||
|
return ((BitmapDrawable) drawable).getBitmap(); |
||||||
|
} |
||||||
|
} |
||||||
|
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); |
||||||
|
} |
||||||
|
} |
||||||
|
return bitmap; |
||||||
|
} |
||||||
|
|
||||||
|
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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue