这个主要想分享一下,类似彩带快速飞行的动效,主要可以作用于飞入购物车动效。飞机飞行尾气跟随动效等。主要灵感来自于很多小游戏里的点击飞行特效。先看看效果:
先看看尾部不停的闪耀和不停地产生新的star开始,原理就是给定一个角度,然后随机生成偏移量。在给定角度内,不停的使用Paint画出bitmap,然后不停的随机计算位置,然后再给上透明度的变化就可以了。
private void init() {
// 0~360
float direction;
if (mAngle >= 0 && mAngle < 90) {
// 270~360
direction = 270 + mAngle;
} else if (mAngle >= 90 && mAngle < 180) {
// 0~90
direction = mAngle - 90;
} else if (mAngle >= 180 && mAngle < 270) {
// 90~180
direction = mAngle - 90;
} else {
// 180~270
direction = mAngle - 90;
}
Random random = new Random();
for (int i = 0; i < mCount; i++) {
// 偏移角度在 -15~15
float t = random.nextInt(30) - 15;
t = direction + t;
if (t > 360) {
t = t - 360;
}
if (t < 0) {
t = t + 360;
}
t = (float) Math.toRadians(t);
elements.add(new Element(t, mLaunchSpeed * random.nextFloat()));
}
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.WHITE);
mAnimator = ValueAnimator.ofFloat(1, 0);
mAnimator.setDuration(DEFAULT_DURATION);
mAnimator.setInterpolator(new AccelerateInterpolator());
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animator) {
mAnimatedValue = (float) animator.getAnimatedValue();
// 计算位置
for (Element element : elements) {
element.x += (float) (Math.cos(element.direction) * element.speed) * mAnimatedValue;
element.y += (float) (Math.sin(element.direction) * element.speed) * mAnimatedValue;
}
}
});
mAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (mListener != null)
mListener.onAnimatorEnd();
}
});
}
这么直接将bitmap画上去的就会存在一个问题,就是就是图片显示大小不可控。因此需要将bitmap大小改变下。
public void draw(Canvas canvas) {
mPaint.setAlpha((int) (255 * mAnimatedValue));
Bitmap bitmap = BitmapFactory.decodeResource(BaseApplication.getContext().getResources(), R.mipmap.icon_fly_star);
Random random = new Random();
int radomSize = bitmap.getWidth() / 10 + random.nextInt(bitmap.getWidth() / 2);
bitmap = imageScale(bitmap, radomSize, radomSize);
for (Element element : elements) {
//画圆点性能更高
// canvas.drawCircle(mLocationX + element.x, mLocationY + element.y, mElementSize, mPaint);
canvas.drawBitmap(bitmap, mLocationX + element.x, mLocationY + element.y, mPaint);
}
}
/*
设置bitmap尺寸
*/
public Bitmap imageScale(Bitmap bitmap, int dst_w, int dst_h) {
int src_w = bitmap.getWidth();
int src_h = bitmap.getHeight();
float scale_w = ((float) dst_w) / src_w;
float scale_h = ((float) dst_h) / src_h;
Matrix matrix = new Matrix();
matrix.postScale(scale_w, scale_h);
Bitmap dstbmp = Bitmap.createBitmap(bitmap, 0, 0, src_w, src_h, matrix,
true);
// Random random = new Random();
// return getAlplaBitmap(dstbmp, 20+random.nextInt(80));
return dstbmp;
}
这样就出现了星星不停的闪烁,不停的出现新的星星,剩下的就是移动了,获取两个点的坐标,然后再获取角度,将闪烁的星星进行角度旋转,然后讲这个星星进行移动。从起始点移动到目标点就可以了。
private void moveStartLocation() {
view_anim.setVisibility(View.INVISIBLE);
int[] startlocation = new int[2];
tv_start.getLocationOnScreen(startlocation);
final int startx = startlocation[0];
final int starty = startlocation[1];
int[] targetlocation = new int[2];
tv_target.getLocationOnScreen(targetlocation);
final int targetx = targetlocation[0];
final int targety = targetlocation[1];
rotationBetweenLines = getRotationBetweenLines(targetx, targety, startx, starty);
final int viewSize = dp2px(this, 150);
ObjectAnimator translationX = new ObjectAnimator().ofFloat(view_anim, "translationX", 0, startx + viewSize);
ObjectAnimator translationY = new ObjectAnimator().ofFloat(view_anim, "translationY", 0, starty + viewSize);
AnimatorSet animatorSet = new AnimatorSet(); //组合动画
animatorSet.playTogether(translationX, translationY); //设置动画
animatorSet.setDuration(10); //设置动画时间
animatorSet.start(); //启动
animatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
view_anim.setVisibility(View.VISIBLE);
showFlyAnim(startx - viewSize, starty - viewSize, targetx - viewSize, targety - viewSize);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
private void showFlyAnim(int startx, int starty, int targetx, int targety) {
ObjectAnimator translationX = new ObjectAnimator().ofFloat(view_anim, "translationX", startx, targetx);
ObjectAnimator translationY = new ObjectAnimator().ofFloat(view_anim, "translationY", starty, targety);
AnimatorSet animatorSet = new AnimatorSet(); //组合动画
animatorSet.playTogether(translationX, translationY); //设置动画
animatorSet.setDuration(1000); //设置动画时间
animatorSet.start(); //启动
Message handlemsg = new Message();
handlemsg.what = 1;
mHandler.sendMessage(handlemsg);
translationY.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Log.e("slkdfhjksjss", "========");
}
});
animatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
view_anim.setVisibility(View.GONE);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
private int handlerSize = 0;
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
if (handlerSize < 1000) {
handlerSize += 1;
Message handlemsg = new Message();
handlemsg.what = 1;
mHandler.sendMessageDelayed(handlemsg, 1);
view_anim.start(rotationBetweenLines);
} else {
handlerSize = 0;
view_anim.end();
}
break;
}
}
};
//获取角度
public int getRotationBetweenLines(float centerX, float centerY, float xInView, float yInView) {
double rotation = 0;
double k1 = (double) (centerY - centerY) / (centerX * 2 - centerX);
double k2 = (double) (yInView - centerY) / (xInView - centerX);
double tmpDegree = Math.atan((Math.abs(k1 - k2)) / (1 + k1 * k2)) / Math.PI * 180;
if (xInView > centerX && yInView < centerY) { //第一象限
rotation = 90 - tmpDegree;
} else if (xInView > centerX && yInView > centerY) //第二象限
{
rotation = 90 + tmpDegree;
} else if (xInView < centerX && yInView > centerY) { //第三象限
rotation = 270 - tmpDegree;
} else if (xInView < centerX && yInView < centerY) { //第四象限
rotation = 270 + tmpDegree;
} else if (xInView == centerX && yInView < centerY) {
rotation = 0;
} else if (xInView == centerX && yInView > centerY) {
rotation = 180;
}
return (int) rotation;
}
那么整体就可以实现了。
demo下载地址:https://download.csdn.net/download/greatdaocaoren/12532060