溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android自定義View新年煙花、祝福語橫幅動畫

發(fā)布時間:2020-08-26 21:18:22 來源:腳本之家 閱讀:178 作者:匆忙擁擠repeat 欄目:移動開發(fā)

新年了,項目中要作個動畫,整體要求實現彩帶亂飛,煙花沖天而起,煙花縮放,小雞換圖,小雞飄移,橫幅裁剪、展開等動畫效果,全局大量使用了屬性動畫來實現。

如下效果圖:

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沒有繪制的問題,但是會發(fā)生繪制時不夠平滑,而出現抖動的情形(在某些devices上)
所以最好還是不要使用float來計算
> 后來,同事猜想使用一個固定int值 來參與計算,可能可以解決上述問題:
比如每秒30幀,這里動畫時長2秒,即共30*2=60幀;
圖片寬度、左畫軸、右畫軸  對  60幀數 做相應的除法及其他計算,可得出一個單幀中 它們應該運動的x距離
> 之后,我又想了一種,使用一個屬性動畫,來計算出從0到getWidth()之間的 動畫值,
從而通過計算,使得橫幅從左向右拉開, 如下:

Android自定義View新年煙花、祝福語橫幅動畫

代碼就不整體開源了

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI