需求
在開發(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地址弓颈。?里面還有其他動畫喲,多多支持森爽,點個贊哈恨豁。