今天開始記錄工作中遇到的需要實現的動畫效果實現自定義view動畫,后期會有一些列動畫設計思路的文章。
在這里分享的是設計實現思路,僅供學習使用,讓大家拿到稍微復雜點的動畫的時候要知道該如何去一步步分解實現,而不是抱怨
下邊就先來看看設計需要的效果圖及我們最終實現的效果圖,畢竟有圖有真相嘛!
其實我剛拿到設計圖的時候心想,MD直接給一張gif圖不就行了何必這個麻煩吶,
隨后冷靜下來之后(其實就是抱怨之后)想想作為一名Android開發者總不能什么動畫都依賴設計師吧,那樣的話會顯得我們開發者沒什么卵用啊,說不定還會被設計師鄙視哦,
于是就開始了動畫分析及實現之旅。
通過這個gif動畫我們分析出動畫過程的實質:
一個長方形(或者是圓角長方形)逐漸過渡成為兩邊是半圓的長方形,于此同時長方形兩邊向中間靠攏最終形成一個圓,然后圓上升一定高度,最后在圓里邊畫出對勾(?).整個動畫分解的其實就是這幾個部分,那么我們該如何實現吶,不要捉急,繼續往下看。
第一步:我們要先畫出一個圓角矩形吧
/**
* 繪制帶圓角的矩形
*
* @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
/**
* 設置矩形過度圓角矩形的動畫
*/
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();
}
});
}
添加動畫之后的效果如下
第二步:當矩形兩邊都是半圓之后就要處理使其向中間靠攏逐漸形成一個圓,那么問題又來了,需要向中間移動多少吶,并且怎么移動才能使兩邊都想中間聚攏吶
下邊來看一張圖分析一下
有圖可知移動的距離是(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();
}
});
}
完成上邊代碼后再來看下效果
第三步:讓圓上移移動距離。這個移動很好實現,直接改變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就能實現動態繪制對勾的效果了,那么怎么計算對勾的起點折點和終點的坐標吶,在網上找了一個不錯的圖片,如果你的設計師直接把位置給你標明的很詳細的話你就省了這些自己計算的麻煩
/**
* 繪制對勾
* 下邊計算比例是參考網上一些例子加上自己一步一步嘗試的出來的比例,僅供參考
* 如果條件允許最好還是讓設計師給你標明一下比例哦!
*/
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();
}
});
}
再來看效果
至此動畫分解都已完成,但是機智的你應該已經發現問題了,就是感覺動畫播放銜接的不是很好,那么接下來我們就處理這個問題,回到最初的效果圖上,矩形變圓角和縮放成圓形是同時進行的,那么我們有什么辦法可以實現動畫同時播放吶,哈哈,身為老司機的想必已經知道了使用AnimatorSet,他可以播放動畫集、順序播放等,那么我們就開始處理吧
我們讓矩形變圓角和矩形往中間縮放同時進行,然后圓在上移,最后繪制對勾
animatorSet
.play(animator_move_to_up)
.before(animator_draw_ok)
.after(animator_rect_to_square)
.after(animator_rect_to_angle);
最終奉上我們自己一步一步完整實現的效果圖
至此我們可以理直氣壯地帶著作品找設計師互懟了