您好,登錄后才能下訂單哦!
新年了,項目中要作個動畫,整體要求實現彩帶亂飛,煙花沖天而起,煙花縮放,小雞換圖,小雞飄移,橫幅裁剪、展開等動畫效果,全局大量使用了屬性動畫來實現。
如下效果圖:
我在實現過程中,橫幅的裁剪計算,搗騰了比較久的時間,初版采用屬性動畫計算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()之間的 動畫值,
從而通過計算,使得橫幅從左向右拉開, 如下:
代碼就不整體開源了
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。