2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > android 烟花动画效果图 Android 自定义 View 新年烟花 横幅动画

android 烟花动画效果图 Android 自定义 View 新年烟花 横幅动画

时间:2018-12-19 17:59:41

相关推荐

android 烟花动画效果图 Android 自定义 View 新年烟花 横幅动画

新年了,项目中要作个动画,如下效果图:

整体要求实现:彩带乱飞,烟花冲天而起,烟花缩放,小鸡换图,小鸡飘移,横幅裁剪、展开等动画效果,

全局大量使用了属性动画来实现。

我在实现过程中,横幅的裁剪计算,捣腾了比较久的时间,初版采用属性动画计算float的一个比率值,来配合每一帧的裁剪绘制,如下代码:

privatestaticclassRollViewextendsView{

privateBitmapmBitmap;

privateRectmSrc;

privateRectmDst;

privateintmRollWidth=60;

privatefloatmRate;

privatebooleanmIsStopAnim;

publicRollView(Contextcontext){

super(context);

mSrc=newRect();

mDst=newRect();

}

@Override

protectedvoidonMeasure(intwidthMeasureSpec, intheightMeasureSpec){

super.onMeasure(widthMeasureSpec,heightMeasureSpec);

}

@Override

protectedvoidonDraw(Canvascanvas){

if(mBitmap==null)return;

drawFromMiddleByFloatCompute(canvas);

}

privatevoiddrawFromMiddleByFloatCompute(Canvascanvas){

/*

以下src都需要加上mBitmap.的前缀,,因从drawable拿到的是原始图片宽高

而适配时,可能view的宽高比drawable的宽高还小或大

*/

finalfloatrate=mRate;

mSrc.left=0;

mSrc.top=0;

mSrc.right=mRollWidth;

mSrc.bottom=mBitmap.getHeight();

mDst.left=(int)((getWidth()/2-mRollWidth)-(getWidth()/ 2-mRollWidth)*rate);

mDst.top=0;

mDst.right=mDst.left+mRollWidth+1;//因精度问题,这里强制+1

mDst.bottom=getHeight();

canvas.drawBitmap(mBitmap,mSrc,mDst,null);

//中间

intsw=(int)((mBitmap.getWidth()-mRollWidth* 2)*rate);

mSrc.left=mBitmap.getWidth()/2-sw/2;

mSrc.top=0;

mSrc.right=mSrc.left+sw;

mSrc.bottom=mBitmap.getHeight();

intdw=(int)((getWidth()-mRollWidth* 2)*rate);

mDst.left=getWidth()/2-dw/2;

mDst.top=0;

mDst.right=mDst.left+dw;

mDst.bottom=getHeight();

canvas.drawBitmap(mBitmap,mSrc,mDst,null);

//右边

mSrc.left=mBitmap.getWidth()-mRollWidth;

mSrc.top=0;

mSrc.right=mBitmap.getWidth();

mSrc.bottom=mBitmap.getHeight();

mDst.left=(int)(getWidth()/2+(getWidth()/ 2-mRollWidth)*rate);

mDst.top=0;

mDst.right=mDst.left+mRollWidth;

mDst.bottom=getHeight();

canvas.drawBitmap(mBitmap,mSrc,mDst,null);

}

publicvoidsetRes(intresId){

mBitmap=getBitmapFromLocal(resId);

}

@RequiresApi(api=Build.VERSION_CODES.HONEYCOMB)

publicvoidstartFloatComputeAnim(){

/*

如果有float获取比率值,从而计算出相应的坐标值,那么可能由于最终在转成Rect的坐标时,

floattoint,有精度的损失:1个px而引起效果的不理想

*/

ValueAnimatoranimator=ValueAnimator.ofFloat(0,1);

animator.addUpdateListener(newValueAnimator.AnimatorUpdateListener(){

@Override

publicvoidonAnimationUpdate(ValueAnimatoranimation){

if(mIsStopAnim){

animation.cancel();

return;

}

mRate=(float)animation.getAnimatedValue();

invalidate();

}

});

animator.setDuration(2000);

animator.start();

}

publicvoidstopAnim(){

mIsStopAnim=true;

}

}

private static class RollView extends View {

private Bitmap mBitmap;

private Rect mSrc;

private Rect mDst;

private int mRollWidth = 60;

private float mRate;

private boolean mIsStopAnim;

public RollView(Context context) {

super(context);

mSrc = new Rect();

mDst = new Rect();

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

}

@Override

protected void onDraw(Canvas canvas) {

if (mBitmap == null) return;

drawFromMiddleByFloatCompute(canvas);

}

private void drawFromMiddleByFloatCompute(Canvas canvas) {

/*

以下src 都需要加上mBitmap. 的前缀,, 因从drawable拿到的是原始图片宽高

而适配时,可能view的宽高比 drawable的宽高还小或大

*/

final float rate = mRate;

mSrc.left = 0;

mSrc.top = 0;

mSrc.right = mRollWidth;

mSrc.bottom = mBitmap.getHeight();

mDst.left = (int) ((getWidth() / 2 - mRollWidth) - (getWidth() / 2 - mRollWidth) * rate);

mDst.top = 0;

mDst.right = mDst.left + mRollWidth + 1;//因精度问题,这里强制+1

mDst.bottom = getHeight();

canvas.drawBitmap(mBitmap, mSrc, mDst, null);

//中间

int sw = (int) ((mBitmap.getWidth() - mRollWidth * 2) * rate);

mSrc.left = mBitmap.getWidth() / 2 - sw / 2;

mSrc.top = 0;

mSrc.right = mSrc.left + sw;

mSrc.bottom = mBitmap.getHeight();

int dw = (int) ((getWidth() - mRollWidth * 2) * rate);

mDst.left = getWidth() / 2 - dw / 2;

mDst.top = 0;

mDst.right = mDst.left + dw;

mDst.bottom = getHeight();

canvas.drawBitmap(mBitmap, mSrc, mDst, null);

//右边

mSrc.left = mBitmap.getWidth() - mRollWidth;

mSrc.top = 0;

mSrc.right = mBitmap.getWidth();

mSrc.bottom = mBitmap.getHeight();

mDst.left = (int) (getWidth() / 2 + (getWidth() / 2 - mRollWidth) * rate);

mDst.top = 0;

mDst.right = mDst.left + mRollWidth;

mDst.bottom = getHeight();

canvas.drawBitmap(mBitmap, mSrc, mDst, null);

}

public void setRes(int resId) {

mBitmap = getBitmapFromLocal(resId);

}

@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)

public void startFloatComputeAnim() {

/*

如果有float获取比率值,从而计算出相应的坐标值,那么可能由于最终在转成Rect的坐标时,

float to int ,有精度的损失:1个px 而引起效果的不理想

*/

ValueAnimator animator = ValueAnimator.ofFloat(0, 1);

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

if (mIsStopAnim) {

animation.cancel();

return;

}

mRate = (float) animation.getAnimatedValue();

invalidate();

}

});

animator.setDuration(2000);

animator.start();

}

public void stopAnim() {

mIsStopAnim = true;

}

}复制代码

>因float转int有一个精度损失的问题,所以在计算中强制加上了1px(代码中有);

这样虽然解决了有1px没有绘制的问题,但是会发生绘制时不够平滑,而出现抖动的情形(在某些devices上)

所以最好还是不要使用float来计算

> 后来,同事猜想使用一个固定int值 来参与计算,可能可以解决上述问题:

比如每秒30帧,这里动画时长2秒,即共30*2=60帧;

图片宽度、左画轴、右画轴 对 60帧数 做相应的除法及其他计算,可得出一个单帧中 它们应该运动的x距离

> 之后,我又想了一种,使用一个属性动画,来计算出从0到getWidth()之间的 动画值,

从而通过计算,使得横幅从左向右拉开, 如下:

代码就不整体开源了···

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。