Commit 3e1b1fe1 by wjg

v2

parent 2cf223b5
package com.ihaoin.hooloo.device.component.particlesmasher;
import android.app.Presentation;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import java.util.ArrayList;
import java.util.List;
/**
* <pre>
* author : FaDai
* e-mail : i_fadai@163.com
* time : 2017/12/14
* desc : xxxx描述
* version: 1.0
* </pre>
*/
public class ParticleSmasher extends View {
private List<SmashAnimator> mAnimators = new ArrayList<>();
private Canvas mCanvas;
private Presentation mActivity;
public ParticleSmasher(Presentation activity) {
super((Context) activity.getContext());
this.mActivity = activity;
addView2Window(activity);
init();
}
/**
* 添加View到当前界面
*/
private void addView2Window(Presentation activity) {
ViewGroup rootView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);
// 需要足够的空间展现动画,因此这里使用的是充满父布局
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
rootView.addView(this, layoutParams);
}
private void init() {
mCanvas = new Canvas();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (SmashAnimator animator : mAnimators) {
animator.draw(canvas);
}
}
public SmashAnimator with(View view) {
// 每次都新建一个单独的SmashAnimator对象
SmashAnimator animator = new SmashAnimator(this, view);
mAnimators.add(animator);
return animator;
}
/**
* 获取View的Rect,并去掉状态栏、toolbar高度
* @param view 来源View
* @return 获取到的Rect
*/
public Rect getViewRect(View view) {
Rect rect = new Rect();
view.getGlobalVisibleRect(rect);
int[] location = new int[2];
getLocationOnScreen(location);
rect.offset(-location[0], -location[1]);
return rect;
}
/**
* 获取View的Bitmap
* @param view 来源View
* @return 获取到的图片
*/
public Bitmap createBitmapFromView(View view) {
view.clearFocus();
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
if (bitmap != null) {
synchronized (mCanvas) {
Canvas canvas = mCanvas;
canvas.setBitmap(bitmap);
view.draw(canvas);
canvas.setBitmap(null);
}
}
return bitmap;
}
/**
* 移除动画
* @param animator 需要移除的动画
*/
public void removeAnimator(SmashAnimator animator) {
if (mAnimators.contains(animator)) {
mAnimators.remove(animator);
}
}
/**
* 清除所有动画
*/
public void clear() {
mAnimators.clear();
invalidate();
}
/**
* 让View重新显示
* @param view 已经隐藏的View
*/
public void reShowView(View view) {
view.animate().setDuration(100).setStartDelay(0).scaleX(1).scaleY(1).translationX(0).translationY(0).alpha(1).start();
}
}
package com.ihaoin.hooloo.device.component.particlesmasher;
import android.content.res.Resources;
/**
* <pre>
* author : FaDai
* e-mail : i_fadai@163.com
* time : 2017/12/04
* desc : xxxx描述
* version: 1.0
* </pre>
*/
public class Utils {
private static final float DENSITY = Resources.getSystem().getDisplayMetrics().density;
/**
* dp转换px
* @param dp dp值
* @return 转换后的px值
*/
public static int dp2Px(int dp) {
return Math.round(dp * DENSITY);
}
}
package com.ihaoin.hooloo.device.component.particlesmasher.particle;
import android.graphics.Point;
import android.graphics.Rect;
import java.util.Random;
/**
* <pre>
* author : FaDai
* e-mail : i_fadai@163.com
* time : 2017/12/20
* desc : 下落粒子的实体类
* version: 1.0
* </pre>
*/
public class DropParticle extends Particle {
/**
* 生成粒子
* @param point 粒子在图片中原始位置
* @param color 粒子颜色
* @param radius 粒子的半径
* @param rect View区域的矩形
* @param endValue 动画的结束值
* @param random 随机数
* @param horizontalMultiple 水平变化幅度
* @param verticalMultiple 垂直变化幅度
*/
public DropParticle(Point point, int color, int radius, Rect rect, float endValue, Random random, float horizontalMultiple, float verticalMultiple){
this.color = color;
alpha = 1;
// 参与横向变化参数和竖直变化参数计算,规则:横向参数相对值越大,竖直参数越小
float nextFloat = random.nextFloat();
baseRadius = getBaseRadius(radius, random, nextFloat);
this.radius = baseRadius;
horizontalElement = getHorizontalElement(rect, random, nextFloat, horizontalMultiple);
verticalElement = getVerticalElement(rect, random, nextFloat, verticalMultiple);
baseCx = point.x;
baseCy = point.y;
cx = baseCx;
cy = baseCy;
font = endValue / 10 * random.nextFloat();
later = 0.4f * random.nextFloat();
}
private static float getBaseRadius(float radius, Random random, float nextFloat) {
// 下落和飘落的粒子,其半径很大概率大于初始设定的半径
float r = radius + radius * (random.nextFloat() - 0.5f) * 0.5f;
r = nextFloat < 0.6f ? r :
nextFloat < 0.8f ? r * 1.4f : r * 1.6f;
return r;
}
private static float getHorizontalElement(Rect rect, Random random, float nextFloat, float horizontalMultiple) {
// 第一次随机运算:h=width*±(0.01~0.49)
float horizontal = rect.width() * (random.nextFloat() - 0.5f);
// 第二次随机运行: h= 1/5概率:h;3/5概率:h*0.6; 1/5概率:h*0.3; nextFloat越大,h越小。
horizontal = nextFloat < 0.2f ? horizontal :
nextFloat < 0.8f ? horizontal * 0.6f : horizontal * 0.3f;
// 上面的计算是为了让横向变化参数有随机性,下面的计算是修改横向变化的幅度。
return horizontal * horizontalMultiple;
}
private static float getVerticalElement(Rect rect, Random random, float nextFloat, float verticalMultiple) {
// 第一次随机运算: v=height*(0.5~1)
float vertical = rect.height() * (random.nextFloat() * 0.5f + 0.5f);
// 第二次随机运行: v= 1/5概率:v;3/5概率:v*1.2; 1/5概率:v*1.4; nextFloat越大,h越大。
vertical = nextFloat < 0.2f ? vertical :
nextFloat < 0.8f ? vertical * 1.2f : vertical * 1.4f;
// 上面的计算是为了让变化参数有随机性,下面的计算是变化的幅度。
return vertical * verticalMultiple;
}
public void advance(float factor, float endValue) {
// 动画进行到了几分之几
float normalization = factor / endValue;
if (normalization < font ) {
alpha = 1;
return;
}
if ( normalization > 1f - later) {
alpha = 0;
return;
}
alpha = 1;
// 粒子可显示的状态中,动画实际进行到了几分之几
normalization = (normalization - font) / (1f - font - later);
// 动画超过7/10,则开始逐渐变透明
if (normalization >= 0.7f) {
alpha = 1f - (normalization - 0.7f) / 0.3f;
}
float realValue = normalization * endValue;
// y=j+k*x,j、k都是常数,x为 0~1.4
cx = baseCx + horizontalElement * realValue;
// 下落粒子,y轴持续增大
cy = baseCy + verticalElement * realValue;
radius = baseRadius + baseRadius / 6 * realValue;
}
}
package com.ihaoin.hooloo.device.component.particlesmasher.particle;
import android.graphics.Rect;
import java.util.Random;
/**
* <pre>
* author : FaDai
* e-mail : i_fadai@163.com
* time : 2017/12/14
* desc : 爆炸粒子
* version: 1.0
* </pre>
*/
public class ExplosionParticle extends Particle{
/**
* 生成粒子
*
* @param color 粒子颜色
* @param radius 粒子的半径
* @param rect View区域的矩形
* @param endValue 动画的结束值
* @param random 随机数
* @param horizontalMultiple 水平变化幅度
* @param verticalMultiple 垂直变化幅度
*/
public ExplosionParticle( int color, int radius, Rect rect, float endValue, Random random, float horizontalMultiple, float verticalMultiple){
this.color = color;
alpha = 1;
// 参与横向变化参数和竖直变化参数计算,规则:横向参数相对值越大,竖直参数越小
float nextFloat = random.nextFloat();
baseRadius = getBaseRadius(radius, random, nextFloat);
this.radius = baseRadius;
horizontalElement = getHorizontalElement(rect, random, nextFloat, horizontalMultiple);
verticalElement = getVerticalElement(rect, random, nextFloat, verticalMultiple);
int offsetX = rect.width() / 4;
int offsetY = rect.height() / 4;
// baseCx,baseCy在中心点四周的offset/2的范围内。
baseCx = rect.centerX() + offsetX * (random.nextFloat() - 0.5f);
baseCy = rect.centerY() + offsetY * (random.nextFloat() - 0.5f);
cx = baseCx;
cy = baseCy;
font = endValue / 10 * random.nextFloat();
later = 0.4f * random.nextFloat();
}
private static float getBaseRadius(float radius, Random random, float nextFloat) {
float r = radius + radius * (random.nextFloat() - 0.5f) * 0.5f;
r = nextFloat < 0.6f ? r :
nextFloat < 0.8f ? r * 1.4f : r * 0.8f;
return r;
}
private static float getHorizontalElement(Rect rect, Random random, float nextFloat,float horizontalMultiple) {
// 第一次随机运算:h=width*±(0.01~0.49)
float horizontal = rect.width() * (random.nextFloat() - 0.5f);
// 第二次随机运行: h= 1/5概率:h;3/5概率:h*0.6; 1/5概率:h*0.3; nextFloat越大,h越小。
horizontal = nextFloat < 0.2f ? horizontal :
nextFloat < 0.8f ? horizontal * 0.6f : horizontal * 0.3f;
// 上面的计算是为了让横向变化参数有随机性,下面的计算是修改横向变化的幅度。
return horizontal * horizontalMultiple;
}
private static float getVerticalElement(Rect rect, Random random, float nextFloat,float verticalMultiple) {
// 第一次随机运算: v=height*(0.5~1)
float vertical = rect.height() * (random.nextFloat() * 0.5f + 0.5f);
// 第二次随机运行: v= 1/5概率:v;3/5概率:v*1.2; 1/5概率:v*1.4; nextFloat越大,h越大。
vertical = nextFloat < 0.2f ? vertical :
nextFloat < 0.8f ? vertical * 1.2f : vertical * 1.4f;
// 上面的计算是为了让变化参数有随机性,下面的计算是变化的幅度。
return vertical * verticalMultiple;
}
public void advance(float factor, float endValue) {
// 动画进行到了几分之几
float normalization = factor / endValue;
if (normalization < font || normalization > 1f - later) {
alpha = 0;
return;
}
alpha = 1;
// 粒子可显示的状态中,动画实际进行到了几分之几
normalization = (normalization - font) / (1f - font - later);
// 动画超过7/10,则开始逐渐变透明
if (normalization >= 0.7f) {
alpha = 1f - (normalization - 0.7f) / 0.3f;
}
float realValue = normalization * endValue;
// y=j+k*x,j、k都是常数,x为 0~1.4
cx = baseCx + horizontalElement * realValue;
// y=j+k*(x*(x-1),j、k都是常数,x为 0~1.4
cy = baseCy + verticalElement * (realValue * (realValue - 1));
radius = baseRadius + baseRadius / 4 * realValue;
}
}
package com.ihaoin.hooloo.device.component.particlesmasher.particle;
import android.graphics.Point;
import android.graphics.Rect;
import java.util.Random;
/**
* <pre>
* author : FaDai
* e-mail : i_fadai@163.com
* time : 2017/12/20
* desc : 飘落粒子
* version: 1.0
* </pre>
*/
public class FloatParticle extends Particle {
private float top;
private float left;
public static final int ORIENTATION_LEFT=1,ORIENTATION_RIGHT=2,ORIENTATION_TOP=3,ORIENTATION_BOTTOM=4;
// 方向
private int orientation=ORIENTATION_TOP;
/**
* 生成粒子
* @param orientation 方向
* @param point 粒子在图片中的位置
* @param color 粒子颜色
* @param radius 粒子的半径
* @param rect View区域的矩形
* @param endValue 动画的结束值
* @param random 随机数
* @param horizontalMultiple 水平变化幅度
* @param verticalMultiple 垂直变化幅度
*/
public FloatParticle(int orientation,Point point, int color, int radius, Rect rect, float endValue, Random random, float horizontalMultiple, float verticalMultiple){
this.color = color;
alpha = 1;
// 参与横向变化参数和竖直变化参数计算,规则:横向参数相对值越大,竖直参数越小
float nextFloat = random.nextFloat();
baseRadius = getBaseRadius(radius, random, nextFloat);
this.radius = baseRadius;
horizontalElement = getHorizontalElement(rect, random, nextFloat, horizontalMultiple);
verticalElement = getVerticalElement(rect, random, nextFloat, verticalMultiple);
baseCx = point.x;
baseCy = point.y;
cx = baseCx;
cy = baseCy;
font = endValue / 10 * random.nextFloat();
later = 0.4f * random.nextFloat();
left=(baseCx-rect.left)/rect.width();
top=(baseCy-rect.top)/rect.height();
this.orientation=orientation;
}
private static float getBaseRadius(float radius, Random random, float nextFloat) {
// 下落和飘落的粒子,其半径很大概率大于初始设定的半径
float r = radius + radius * (random.nextFloat() - 0.5f) * 0.5f;
r = nextFloat < 0.6f ? r :
nextFloat < 0.8f ? r * 1.4f : r * 1.6f;
return r;
}
private static float getHorizontalElement(Rect rect, Random random, float nextFloat, float horizontalMultiple) {
// 第一次随机运算:h=width*±(0.01~0.49)
float horizontal = rect.width() * (random.nextFloat() - 0.5f);
// 第二次随机运行: h= 1/5概率:h;3/5概率:h*0.6; 1/5概率:h*0.3; nextFloat越大,h越小。
horizontal = nextFloat < 0.2f ? horizontal :
nextFloat < 0.8f ? horizontal * 0.6f : horizontal * 0.3f;
// 上面的计算是为了让横向变化参数有随机性,下面的计算是修改横向变化的幅度。
return horizontal * horizontalMultiple;
}
private static float getVerticalElement(Rect rect, Random random, float nextFloat, float verticalMultiple) {
// 第一次随机运算: v=height*(0.5~1)
float vertical = rect.height() * (random.nextFloat() * 0.5f + 0.5f);
// 第二次随机运行: v= 1/5概率:v;3/5概率:v*1.2; 1/5概率:v*1.4; nextFloat越大,h越大。
vertical = nextFloat < 0.2f ? vertical :
nextFloat < 0.8f ? vertical * 1.2f : vertical * 1.4f;
// 上面的计算是为了让变化参数有随机性,下面的计算是变化的幅度。
return vertical * verticalMultiple;
}
public void advance(float factor, float endValue) {
// 动画进行到了几分之几
float normalization = factor / endValue;
if (normalization < font ) {
alpha = 1;
return;
}
if ( normalization > 1f - later) {
alpha = 0;
return;
}
alpha = 1;
// 粒子可显示的状态中,动画实际进行到了几分之几
normalization = (normalization - font) / (1f - font - later);
// 动画超过7/10,则开始逐渐变透明
if (normalization >= 0.7f) {
alpha = 1f - (normalization - 0.7f) / 0.3f;
}
float realValue = normalization * endValue;
// 重点:这里使用了realValue(0~1),而不是normalization(0~1.4)。如果使用nor的话,在最后面开始飘落的粒子就会全透明看不到了。
switch (orientation){
case ORIENTATION_LEFT:
if(realValue>left){
cy=baseCy+verticalElement*(realValue-left);
cx = baseCx + horizontalElement * (realValue-left);
}
break;
case ORIENTATION_RIGHT:
if(realValue>(1-left)){
cy=baseCy+verticalElement*(realValue-(1-left));
cx = baseCx + horizontalElement * (realValue-(1-left));
}
break;
case ORIENTATION_TOP:
if(realValue>top){
cy=baseCy+verticalElement*(realValue-top);
cx = baseCx + horizontalElement * (realValue-top);
}
break;
case ORIENTATION_BOTTOM:
if(realValue>(1-top)){
cy=baseCy+verticalElement*(realValue-(1-top));
cx = baseCx + horizontalElement * (realValue-(1-top));
}
break;
}
radius = baseRadius + baseRadius / 6 * realValue;
}
}
package com.ihaoin.hooloo.device.component.particlesmasher.particle;
/**
* <pre>
* author : FaDai
* e-mail : i_fadai@163.com
* time : 2017/12/20
* desc : xxxx描述
* version: 1.0
* </pre>
*/
public abstract class Particle {
public int color; // 颜色
public float radius; // 半径
public float alpha; // 透明度(0~1)
public float cx; // 圆心 x
public float cy; // 圆心 y
public float horizontalElement; // 水平变化参数
public float verticalElement; // 垂直变化参数
public float baseRadius; // 初始半径,同时负责半径大小变化
public float baseCx; // 初始圆心 x
public float baseCy; // 初始圆心 y
public float font; // 决定了粒子在动画开始多久之后,开始显示
public float later; // 决定了粒子动画结束前多少时间开始隐藏
public void advance(float factor, float endValue) {
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment