首页 > 系统 > Android > 正文

Android自定义View新年烟花、祝福语横幅动画

2019-10-22 18:16:32
字体:
来源:转载
供稿:网友

新年了,项目中要作个动画,整体要求实现彩带乱飞,烟花冲天而起,烟花缩放,小鸡换图,小鸡飘移,横幅裁剪、展开等动画效果,全局大量使用了属性动画来实现。

如下效果图:

Android,View,新年,烟花,动画

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

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()之间的 动画值,
从而通过计算,使得横幅从左向右拉开, 如下:

Android,View,新年,烟花,动画

代码就不整体开源了

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持VEVB武林网。


注:相关教程知识阅读请移步到Android开发频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表