Android自定義動畫酷炫的提交按鈕

今天開始記錄工作中遇到的需要實現的動畫效果實現自定義view動畫,后期會有一些列動畫設計思路的文章。

在這里分享的是設計實現思路,僅供學習使用,讓大家拿到稍微復雜點的動畫的時候要知道該如何去一步步分解實現,而不是抱怨
下邊就先來看看設計需要的效果圖及我們最終實現的效果圖,畢竟有圖有真相嘛!

99.gif
其實我剛拿到設計圖的時候心想,MD直接給一張gif圖不就行了何必這個麻煩吶,

隨后冷靜下來之后(其實就是抱怨之后)想想作為一名Android開發者總不能什么動畫都依賴設計師吧,那樣的話會顯得我們開發者沒什么卵用啊,說不定還會被設計師鄙視哦,


設計師對你深深的鄙視

于是就開始了動畫分析及實現之旅。


通過這個gif動畫我們分析出動畫過程的實質:

一個長方形(或者是圓角長方形)逐漸過渡成為兩邊是半圓的長方形,于此同時長方形兩邊向中間靠攏最終形成一個圓,然后圓上升一定高度,最后在圓里邊畫出對勾(?).整個動畫分解的其實就是這幾個部分,那么我們該如何實現吶,不要捉急,繼續往下看。

h

第一步:我們要先畫出一個圓角矩形吧

    /**
     * 繪制帶圓角的矩形
     *
     * @param canvas 畫布
     */
      private void draw_oval_to_circle(Canvas canvas) {
      
              //這里是對矩形的位置大小的設置
              rectf.left = two_circle_distance;
              rectf.top = 0;
              rectf.right = width - two_circle_distance;
              rectf.bottom = height;
      
              //畫圓角矩形
              canvas.drawRoundRect(rectf, circleAngle, circleAngle, paint);
      
          }
          
圓角矩形繪制完成之后就是改變圓角半徑的大小使其兩邊形成半圓的效果,那么怎么才能讓他成為半圓吶,來看看一張圖,若要繪制成半圓效果,那么這個圓的直徑就是view自身的高度,那么這個圓的半徑就是height/2
image.png

    /**
     * 設置矩形過度圓角矩形的動畫
     */
    private void set_rect_to_angle_animation() {
        animator_rect_to_angle = ValueAnimator.ofInt(0, height / 2);
        animator_rect_to_angle.setDuration(duration);
        animator_rect_to_angle.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                circleAngle = (int) animation.getAnimatedValue();
                invalidate();
            }
        });
    }

添加動畫之后的效果如下

button_1.gif

第二步:當矩形兩邊都是半圓之后就要處理使其向中間靠攏逐漸形成一個圓,那么問題又來了,需要向中間移動多少吶,并且怎么移動才能使兩邊都想中間聚攏吶

下邊來看一張圖分析一下
Paste_Image.png
有圖可知移動的距離是(width-height)/2,然后在寫一個動畫讓其改變距離最終兩個半圓靠攏在一起形成圓
    /**
     * 設置圓角矩形過度到圓的動畫
     * default_two_circle_distance = (w-h)/2
     */
    private void set_rect_to_circle_animation() {
        animator_rect_to_square = ValueAnimator.ofInt(0, default_two_circle_distance);
        animator_rect_to_square.setDuration(duration);
        animator_rect_to_square.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                two_circle_distance = (int) animation.getAnimatedValue();

                //在靠攏的過程中設置文字的透明度,使文字逐漸消失的效果
                int alpha = 255 - (two_circle_distance * 255) / default_two_circle_distance;

                textPaint.setAlpha(alpha);

                invalidate();
            }
        });
    }

完成上邊代碼后再來看下效果

button_2.gif

第三步:讓圓上移移動距離。這個移動很好實現,直接改變Y軸方法的坐標就行了,這個很簡單就直接看代碼吧

    /**
     * 設置view上移的動畫
     */
    private void set_move_to_up_animation() {
        final float curTranslationY = this.getTranslationY();
        animator_move_to_up = ObjectAnimator.ofFloat(this, "translationY", curTranslationY, curTranslationY - move_distance);
        animator_move_to_up.setDuration(duration);
        animator_move_to_up.setInterpolator(new AccelerateDecelerateInterpolator());
    }
    

第四步:在圓中繪制一個對勾,而且是帶動畫的對勾,讓對勾以動畫的形式慢慢繪制出來

如果對相關API不熟悉的話不知道會怎么去實現吶,或許你會想通過繪制線的方式,在對勾起點開始不斷改變移動點的坐標進行繪制,那么怎么獲取這些點的坐標吶,這里我們使用Path和DashPathEffect兩個方法實現,對DashPathEffect不了解的小伙伴可以去查一下文檔哦

DashPathEffect這個類的作用就是將Path的線段虛線化。
構造函數為DashPathEffect(float[] intervals, float offset),其中intervals為虛線的ON和OFF數組,該數組的length必須大于等于2,phase為繪制時的偏移量。

我們先拿到對勾的path路徑在對其改變偏移量加上DashPathEffect就能實現動態繪制對勾的效果了,那么怎么計算對勾的起點折點和終點的坐標吶,在網上找了一個不錯的圖片,如果你的設計師直接把位置給你標明的很詳細的話你就省了這些自己計算的麻煩
對勾的繪制位置.jpg
  /**
    * 繪制對勾     
    * 下邊計算比例是參考網上一些例子加上自己一步一步嘗試的出來的比例,僅供參考
    * 如果條件允許最好還是讓設計師給你標明一下比例哦!
    */
   private void initOk() {
       //對勾的路徑
       path.moveTo(default_two_circle_distance + height / 8 * 3, height / 2);
       path.lineTo(default_two_circle_distance + height / 2, height / 5 * 3);
       path.lineTo(default_two_circle_distance + height / 3 * 2, height / 5 * 2);

       pathMeasure = new PathMeasure(path, true);

   }


    /**
     * 繪制對勾的動畫
     */
    private void set_draw_ok_animation() {
        animator_draw_ok = ValueAnimator.ofFloat(1, 0);
        animator_draw_ok.setDuration(duration);
        animator_draw_ok.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                startDrawOk = true;
                float value = (Float) animation.getAnimatedValue();

                effect = new DashPathEffect(new float[]{pathMeasure.getLength(), pathMeasure.getLength()}, value * pathMeasure.getLength());
                okPaint.setPathEffect(effect);
                invalidate();
            }
        });
    }

再來看效果

繪制對勾.gif

至此動畫分解都已完成,但是機智的你應該已經發現問題了,就是感覺動畫播放銜接的不是很好,那么接下來我們就處理這個問題,回到最初的效果圖上,矩形變圓角和縮放成圓形是同時進行的,那么我們有什么辦法可以實現動畫同時播放吶,哈哈,身為老司機的想必已經知道了使用AnimatorSet,他可以播放動畫集、順序播放等,那么我們就開始處理吧

我們讓矩形變圓角和矩形往中間縮放同時進行,然后圓在上移,最后繪制對勾

        animatorSet
                .play(animator_move_to_up)
                .before(animator_draw_ok)
                .after(animator_rect_to_square)
                .after(animator_rect_to_angle);

最終奉上我們自己一步一步完整實現的效果圖

button_animation.gif

至此我們可以理直氣壯地帶著作品找設計師互懟了


向設計師拋出詭異的手勢

總結:看到這里是不是覺得這樣的動畫實現起來也不是很復雜嘛,也許你會覺得這樣的動畫沒什么技術含量,實現起來真的沒什么難度,何必再此大做文章吶,其實我這里也只是個拋磚引玉的作用,提供一種學習方法,也許今天我們遇到的只是一個簡單的動畫,可明天如果需要我們去做更復雜的動畫吶,我們該怎么處理,怎么分析,怎么實現吶。只要我們把自己的需求分析拆解,把復雜的步驟簡單化,分布實現在組合到一起就可以實現自己想要的效果(你要知道炫酷的電影特效也是一幀一幀動畫合成的哦)。

學無止境

源碼已經上傳到github上了,需要參考學習的點擊傳送門

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,401評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,011評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,263評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,543評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,323評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,874評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,968評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,095評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,605評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,551評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,720評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,242評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,961評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,358評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,612評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,330評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,690評論 2 370

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,581評論 25 707
  • 在iOS中隨處都可以看到絢麗的動畫效果,實現這些動畫的過程并不復雜,今天將帶大家一窺ios動畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,533評論 6 30
  • 在iOS中隨處都可以看到絢麗的動畫效果,實現這些動畫的過程并不復雜,今天將帶大家一窺iOS動畫全貌。在這里你可以看...
    F麥子閱讀 5,130評論 5 13
  • 前言 最近項目中新增了一個搶購模塊,需要一個進度指示條,UI設計了幾款出來后,PM一看,不行,太low了,沒有逼...
    luckyzh閱讀 8,203評論 16 55
  • 從確定來英國求學到踏上這片國土,真的經歷了幾個月的忐忑,太多的“前車之鑒”讓我擔憂著不同的種族、不同的文化到底能帶...
    張玲Linda閱讀 351評論 0 0