需求
在開發(fā)中,有這樣的需求,view在某種操作下會有抽屜的展示,而且里面的文字會有翻滾的效果,如下:

即列表向上滑動時,旁邊的氣泡會折疊(并未折疊所有),向下滑動時,氣泡會展開,當(dāng)有新內(nèi)容時,里面的文字內(nèi)容會翻滾顯示。
實現(xiàn)
所有的效果都是通過Canvans來實現(xiàn),也是希望借該博客來和大家來分享一下,當(dāng)開發(fā)時視覺需要實現(xiàn)某些動畫效果時,第一想到的不是通過Google去搜索別人的實現(xiàn),然后去套用,而是沉下心來去思考,去分解動畫,然后通過Canvas去實現(xiàn),當(dāng)你這樣做以后,你會發(fā)現(xiàn)實際上并非這么難,才能以不變應(yīng)萬變。這樣當(dāng)需求改變時,才能很快的解決。
抽屜效果
-
分解展開動畫
?上圖可以看出,動畫從第一幅圖到最后一幅圖右邊的圓角是不變的,這時候很容易就有思路,假設(shè)整個動畫的持續(xù)時間是500ms,我們只需要在500ms之內(nèi)勻速?繪制一個半圓角矩形就可以了。
-
代碼實現(xiàn)
繪制初始化圓角矩形
private void drawView(Canvas canvas) { mDrawPath.reset(); mDrawPath.addRoundRect(mExpandViewRect, mRadiusRectF, Path.Direction.CW); canvas.drawPath(mDrawPath, mBorderPaint); //繪制背景 mDrawPath.reset(); mDrawPath.addRoundRect(mExpandViewRect, mRadiusRectF, Path.Direction.CW); canvas.drawPath(mDrawPath, mBackPaint); }我們通過Path來繪制半圓角矩形,每個角的角度可以自己設(shè)置。如下代碼:
public void setRadius(float leftTop, float rightTop, float rightBottom, float leftBottom) { mRadiusRectF[0] = leftTop; mRadiusRectF[1] = leftTop; mRadiusRectF[2] = rightTop; mRadiusRectF[3] = rightTop; mRadiusRectF[4] = rightBottom; mRadiusRectF[5] = rightBottom; mRadiusRectF[6] = leftBottom; mRadiusRectF[7] = leftBottom; }當(dāng)外界觸發(fā)展開操作時,設(shè)置當(dāng)前狀態(tài)為從展開到折疊,然后在onDraw函數(shù)里進行繪制,如果設(shè)置動畫時間為500ms。
private void drawExpand2CollapseView(Canvas canvas) { float ratio = getAnimRatio(); float distance = mExpandOrCollapseDistance * ratio; int left = (int) (mBorderWidth + distance); mExpandViewRect.set(left, mExpandViewRect.top, mExpandViewRect.right, mExpandViewRect.bottom); drawView(canvas); drawCollapseText(canvas); if (ratio == 1) { mCurrentStatus = STATUS_COLLAPSE; } else { invalidate(); } } private float getAnimRatio() { long now = System.currentTimeMillis(); float ratio = (now - mStartTime) / mDrawerAnimDuration; return ratio >= 1 ? 1 : ratio; }其中mStartTime是觸發(fā)展開操作的起始時間,通過當(dāng)前時間和起始時間的差值再來除以動畫持續(xù)的時間,得到當(dāng)前的比例,再把比例乘以需要伸縮的那部分距離,就得到當(dāng)前繪制的長度,如果比例為1,則證明時間用完,動畫結(jié)束。大體的思路是這個樣子。
文字在這個過程中怎么處理,完全隨著自己業(yè)務(wù)需要而修改,比方說字體平移,字體變大都可以,只需要拿到這個比例算出值,然后通過canvas來繪制即可,非常方便
翻轉(zhuǎn)效果
android里面的翻轉(zhuǎn)效果很多童鞋會想到用TextSwitcher來實現(xiàn),但是在這種場景下是做不了的,因為首先這個view是一個圓角矩形,如果把他作為TextSwitcher的子view來進行翻轉(zhuǎn),會發(fā)現(xiàn)有圓角哪一側(cè)有很顯然的漏洞,?如下如所示:

所以還是得用Canvas來實現(xiàn)這個動效,視覺要求,當(dāng)有新內(nèi)容來時,里面的文字垂直滾動即可。
-
分解滾動動畫
當(dāng)下一個文字來時,上一個文字向上平移并且透明度變小,新來的文字慢慢平移到中間,并且透明度變大。知道了這么多,代碼寫起來就得心應(yīng)手了。下面截下關(guān)鍵代碼:
-
實現(xiàn)
private void drawNextTextView(Canvas canvas) { drawExpandBack(canvas); float ratio = getNextTextRatio(); String text; Rect bounds; Paint.FontMetricsInt fontMetrics = null; int baseline; float start; if (ratio != 1) { bounds = new Rect(); mTextPaint.getTextBounds(mCurrentText, 0, mCurrentText.length(), bounds); start = mExpandViewRect.left + mLeftTopRectRadius * 0.8f + (mExpandViewRect.width() - mLeftTopRectRadius - bounds.width()) / 2; fontMetrics = mTextPaint.getFontMetricsInt(); baseline = (int) ((mHeight * (1 - ratio) - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top); mTextPaint.setAlpha((int) (255 * (1 - ratio))); canvas.drawText(mCurrentText, start, baseline, mTextPaint); bounds = new Rect(); mTextPaint.getTextBounds(mNextText, 0, mNextText.length(), bounds); start = mExpandViewRect.left + mLeftTopRectRadius * 0.8f + (mExpandViewRect.width() - mLeftTopRectRadius - bounds.width()) / 2; baseline = (int) (((mHeight - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top) + mHeight / 2 * (1 - ratio)); mTextPaint.setAlpha((int) (255 * ratio)); canvas.drawText(mNextText, start, baseline, mTextPaint); postInvalidateDelayed(50); } else { mTextPaint.setAlpha(255); bounds = new Rect(); mTextPaint.getTextBounds(mNextText, 0, mNextText.length(), bounds); fontMetrics = mTextPaint.getFontMetricsInt(); start = mExpandViewRect.left + mLeftTopRectRadius * 0.8f + (mExpandViewRect.width() - mLeftTopRectRadius - bounds.width()) / 2; baseline = ((mHeight - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top); canvas.drawText(mNextText, start, baseline, mTextPaint); String text1 = mNextText; mNextText = mCurrentText; mCurrentText = text1; } }基本思路也是設(shè)置一個動畫時間,算出當(dāng)前變化的比例,通過Canvas來不停的繪制文字達到滾動的效果。如果說需要有更立體的效果,比方說翻滾的過程中字體大小也需要改變,按照這樣的思路,設(shè)置paint的textsize?即可。
好,今天的分享就到這里。這里貼出這個效果的 Github Demo地址。?里面還有其他動畫喲,多多支持,點個贊哈。

