Android Canvas 實現(xiàn)抽屜動畫和翻滾動畫

需求

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市爬迟,隨后出現(xiàn)的幾起案子橘蜜,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,464評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件计福,死亡現(xiàn)場離奇詭異跌捆,居然都是意外死亡,警方通過查閱死者的電腦和手機象颖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評論 3 399
  • 文/潘曉璐 我一進店門佩厚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人说订,你說我怎么就攤上這事抄瓦。” “怎么了陶冷?”我有些...
    開封第一講書人閱讀 169,078評論 0 362
  • 文/不壞的土叔 我叫張陵钙姊,是天一觀的道長。 經(jīng)常有香客問我埂伦,道長煞额,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,979評論 1 299
  • 正文 為了忘掉前任沾谜,我火速辦了婚禮膊毁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘基跑。我一直安慰自己婚温,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 69,001評論 6 398
  • 文/花漫 我一把揭開白布涩僻。 她就那樣靜靜地躺著缭召,像睡著了一般。 火紅的嫁衣襯著肌膚如雪逆日。 梳的紋絲不亂的頭發(fā)上嵌巷,一...
    開封第一講書人閱讀 52,584評論 1 312
  • 那天,我揣著相機與錄音室抽,去河邊找鬼搪哪。 笑死,一個胖子當(dāng)著我的面吹牛坪圾,可吹牛的內(nèi)容都是我干的晓折。 我是一名探鬼主播,決...
    沈念sama閱讀 41,085評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼兽泄,長吁一口氣:“原來是場噩夢啊……” “哼漓概!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起病梢,我...
    開封第一講書人閱讀 40,023評論 0 277
  • 序言:老撾萬榮一對情侶失蹤胃珍,失蹤者是張志新(化名)和其女友劉穎梁肿,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體觅彰,經(jīng)...
    沈念sama閱讀 46,555評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡吩蔑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,626評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了填抬。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片烛芬。...
    茶點故事閱讀 40,769評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖飒责,靈堂內(nèi)的尸體忽然破棺而出赘娄,到底是詐尸還是另有隱情,我是刑警寧澤读拆,帶...
    沈念sama閱讀 36,439評論 5 351
  • 正文 年R本政府宣布擅憔,位于F島的核電站鸵闪,受9級特大地震影響檐晕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蚌讼,卻給世界環(huán)境...
    茶點故事閱讀 42,115評論 3 335
  • 文/蒙蒙 一辟灰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧篡石,春花似錦芥喇、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至胖眷,卻和暖如春武通,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背珊搀。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評論 1 274
  • 我被黑心中介騙來泰國打工冶忱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人境析。 一個月前我還...
    沈念sama閱讀 49,191評論 3 378
  • 正文 我出身青樓囚枪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親劳淆。 傳聞我的和親對象是個殘疾皇子链沼,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,781評論 2 361

推薦閱讀更多精彩內(nèi)容