Android使用Path仿支付寶支付成功失敗動畫

序言:最近空閑的時(shí)候一直在學(xué)習(xí)自定義View的相關(guān)知識,這也是LZ最近半年的學(xué)習(xí)對象植旧,有的時(shí)候就是要給自己定下一個(gè)小目標(biāo),咱們沒有王老板的先賺他一個(gè)億這么豪氣,也得先有個(gè)目標(biāo)不是荚恶。逛博客的時(shí)候看到支付寶支付成功失敗的動畫效果,剛好最近在學(xué)習(xí)Path的相關(guān)知識磷支,就想著實(shí)踐一下谒撼,也鞏固一下自己所學(xué)的知識,話不多說直接上圖雾狈。

這個(gè)也是公司項(xiàng)目中需要的廓潜,之前由于項(xiàng)目緊,直接讓UI切了個(gè)圖善榛,就這樣上了辩蛋,這不太符合我的一貫作風(fēng),但是沒辦法>_<

首先我們來分解一下這個(gè)動作移盆,首先是一段progressDialog悼院,可以看做是在請求數(shù)據(jù)等待過程,然后成功之后顯示成功的動畫咒循,失敗之后顯示失敗的動畫据途,那么這里涉及到三個(gè)狀態(tài),加載中叙甸、加載成功和加載失敗颖医,這里我們使用枚舉來實(shí)現(xiàn)這三種狀態(tài)。首先呢裆蒸,我們先來實(shí)現(xiàn)這個(gè)等待的進(jìn)度條:

1熔萧、畫一個(gè)圓,確切的來說是畫一段圓弧僚祷,然后旋轉(zhuǎn)畫布佛致,在此過程中不斷修改圓弧的大小,造成一個(gè)這樣動態(tài)的假象:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.translate(getPaddingLeft(), getPaddingTop());   //將當(dāng)前畫布的點(diǎn)移到getPaddingLeft,getPaddingTop,后面的操作都以該點(diǎn)作為參照點(diǎn)
    if (mStatus == StatusEnum.Loading) {    //正在加載
        if (startAngle == minAngle) {
            sweepAngle += 6;
        }
        if (sweepAngle >= 300 || startAngle > minAngle) {
            startAngle += 6;
            if (sweepAngle > 20) {
                sweepAngle -= 6;
            }
        }
        if (startAngle > minAngle + 300) {
            startAngle %= 360;
            minAngle = startAngle;
            sweepAngle = 20;
        }
        canvas.rotate(curAngle += 4, progressRadius, progressRadius);  //旋轉(zhuǎn)的弧長為4
        canvas.drawArc(new RectF(0, 0, progressRadius * 2, progressRadius * 2), startAngle, sweepAngle, false, mPaint);
        invalidate();
    }
}

這里startAngle表示圓弧的起始角度辙谜,sweepAngle表示圓弧掃過的角度俺榆,minAngle是一個(gè)過渡值,是為了幫助startAngle改變值而用到的筷弦。這里用到了畫弧度的方法肋演,在上一篇博客中我有細(xì)講這個(gè)方法抑诸,如果你還不知道的話請移步Android自定義view之圓形進(jìn)度條,這里還用到了rotate方法爹殊,來看一下它的源碼解釋:

/**
 * Preconcat the current matrix with the specified rotation.
 *
 * @param degrees The amount to rotate, in degrees
 * @param px The x-coord for the pivot point (unchanged by the rotation)
 * @param py The y-coord for the pivot point (unchanged by the rotation)
 */
public final void rotate(float degrees, float px, float py) {
    translate(px, py);
    rotate(degrees);
    translate(-px, -py);
}

這個(gè)方法主要是將畫布進(jìn)行旋轉(zhuǎn)蜕乡,我們可以看到,先是將畫布平移到某個(gè)點(diǎn)梗夸,然后再旋轉(zhuǎn)某個(gè)角度层玲,最后再平移回去,這樣做的目的是為了讓需要旋轉(zhuǎn)的View進(jìn)行中心對稱旋轉(zhuǎn)反症,所以后面?zhèn)鞯?code>PX,PY值需要是View寬高的一半辛块,不信的話你可以去做個(gè)實(shí)驗(yàn);說了這么多我們直接來看一下效果:

2铅碍、畫成功狀態(tài)的動畫润绵,這部分也可以分成兩個(gè)小部分,先是畫一個(gè)圓胞谈,然后再畫中間的鉤:
(1)尘盼、畫圓:上一篇博客中講了通過進(jìn)度來畫弧進(jìn)而來畫整個(gè)圓,今天我們的主角是Path烦绳,所以我們使用Path來實(shí)現(xiàn)這樣一個(gè)效果卿捎,還是先上代碼,通過代碼來講解:

//追蹤Path的坐標(biāo)
private PathMeasure mPathMeasure;
//畫圓的Path
private Path mPathCircle;
//截取PathMeasure中的path
private Path mPathCircleDst;

mPaint.setColor(loadSuccessColor);
mPathCircle.addCircle(getWidth() / 2, getWidth() / 2, progressRadius, Path.Direction.CW);
mPathMeasure.setPath(mPathCircle, false);
mPathMeasure.getSegment(0, circleValue * mPathMeasure.getLength(), mPathCircleDst, true);
canvas.drawPath(mPathCircleDst, mPaint);

Path的常用方法有径密,add一條路徑(任意形狀午阵,任意線條),這里我們在path中添加了一個(gè)圓的路徑享扔,具體Path常見的用法如下表所示:

Path的常見方法 方法含義
moveTo() 該方法移動后續(xù)操作的起點(diǎn)坐標(biāo)
lineTo() 該方法是連接起始點(diǎn)與某一點(diǎn)(傳的參數(shù))形成一條線
setLastPath() 該方法是設(shè)置Path最后的坐標(biāo)
close() 該方法是將起點(diǎn)坐標(biāo)與終點(diǎn)坐標(biāo)連接起來形成一個(gè)閉合的圖形(如果始終點(diǎn)左邊能連接的話)
addRect() 該方法是繪制一個(gè)巨型
addRoundRect() 該方法是繪制一個(gè)圓角矩形
addOval() 該方法是繪制一個(gè)橢圓
arcTo() 該方法是繪制一段圓弧
addArc() 該方法是繪制一段圓弧

然后呢底桂,這里有一個(gè)PathMeasure,簡單點(diǎn)說伪很,這玩意就是用來實(shí)現(xiàn)Path坐標(biāo)點(diǎn)的追蹤戚啥,你也可以認(rèn)為是Path坐標(biāo)的計(jì)算器,具體PathMeasure的常見的用法如下表所示:

PathMeasure的常見方法 方法含義
setPath() 該方法將path與PathMeasure綁定起來
getLength() 該方法用于獲得path路徑的長度
getSegment() 該方法用于截取整個(gè)Path的片段
nextContour() 該方法用于切換到下一個(gè)路徑

這里我們通過動畫從0——1之間的變化锉试,來改變所畫圓的弧度:

circleAnimator = ValueAnimator.ofFloat(0, 1);
circleAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        circleValue = (float) animation.getAnimatedValue();
        invalidate();
    }
});

(2)、接下來畫完圓之后览濒,我們要開始畫對鉤了:

對鉤
if (circleValue == 1) {      //表示圓畫完了,可以鉤了
    successPath.moveTo(getWidth() / 1 * 3, getWidth() / 2);
    successPath.lineTo(getWidth() / 2, getWidth() / 5 * 3);
    successPath.lineTo(getWidth() / 3 * 2, getWidth() / 5 * 2);
    mPathMeasure.nextContour();
    mPathMeasure.setPath(successPath, false);
    mPathMeasure.getSegment(0, successValue * mPathMeasure.getLength(), mPathCircleDst, true);
    canvas.drawPath(mPathCircleDst, mPaint);
}

這里的坐標(biāo)我是根據(jù)UI給的圖大致算出來的呆盖,可以參考下面這張圖的虛線和實(shí)現(xiàn),對鉤的起始坐標(biāo)在坐標(biāo)軸中大致是getWidth() / 8 * 3贷笛,你也可以根據(jù)你的需求來畫出這個(gè)對鉤应又,其實(shí)就是兩段路徑,分別用pathlineTo方法來實(shí)現(xiàn):

成功畫對勾

同理乏苦,畫叉叉也是一樣的株扛,只要你算出叉在坐標(biāo)軸中的坐標(biāo)就ok了尤筐,這里我也給出一張參考圖:

叉叉
mPaint.setColor(loadFailureColor);
mPathCircle.addCircle(getWidth() / 2, getWidth() / 2, progressRadius, Path.Direction.CW);
mPathMeasure.setPath(mPathCircle, false);
mPathMeasure.getSegment(0, circleValue * mPathMeasure.getLength(), mPathCircleDst, true);
canvas.drawPath(mPathCircleDst, mPaint);

if (circleValue == 1) {  //表示圓畫完了,可以畫叉叉的右邊部分
    failurePathRight.moveTo(getWidth() / 3 * 2, getWidth() / 3);
    failurePathRight.lineTo(getWidth() / 3, getWidth() / 3 * 2);
    mPathMeasure.nextContour();
    mPathMeasure.setPath(failurePathRight, false);
    mPathMeasure.getSegment(0, failValueRight * mPathMeasure.getLength(), mPathCircleDst, true);
    canvas.drawPath(mPathCircleDst, mPaint);
}

if (failValueRight == 1) {    //表示叉叉的右邊部分畫完了,可以畫叉叉的左邊部分
    failurePathLeft.moveTo(getWidth() / 3, getWidth() / 3);
    failurePathLeft.lineTo(getWidth() / 3 * 2, getWidth() / 3 * 2);
    mPathMeasure.nextContour();
    mPathMeasure.setPath(failurePathLeft, false);
    mPathMeasure.getSegment(0, failValueLeft * mPathMeasure.getLength(), mPathCircleDst, true);
    canvas.drawPath(mPathCircleDst, mPaint);
}
失敗畫叉叉

參考:

Android自定義之仿支付寶支付成功、失敗狀態(tài)的加載進(jìn)度

自定義View(三)使用Path仿支付寶支付成功效果

PathMeasure之迷徑追蹤

到此就完成了自定義的原型進(jìn)度條了洞就。源碼已上傳至Github盆繁,有需要的同學(xué)可以下載下來看看,歡迎Star旬蟋,F(xiàn)ork

同時(shí)感謝以上引用到博客的主人油昂,感謝!G惴 冕碟!
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市匆浙,隨后出現(xiàn)的幾起案子安寺,更是在濱河造成了極大的恐慌,老刑警劉巖首尼,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件我衬,死亡現(xiàn)場離奇詭異,居然都是意外死亡饰恕,警方通過查閱死者的電腦和手機(jī)挠羔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來埋嵌,“玉大人破加,你說我怎么就攤上這事”⑧拢” “怎么了范舀?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長了罪。 經(jīng)常有香客問我锭环,道長,這世上最難降的妖魔是什么泊藕? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任辅辩,我火速辦了婚禮,結(jié)果婚禮上娃圆,老公的妹妹穿的比我還像新娘玫锋。我一直安慰自己,他們只是感情好讼呢,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布撩鹿。 她就那樣靜靜地躺著,像睡著了一般悦屏。 火紅的嫁衣襯著肌膚如雪节沦。 梳的紋絲不亂的頭發(fā)上键思,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機(jī)與錄音甫贯,去河邊找鬼吼鳞。 笑死,一個(gè)胖子當(dāng)著我的面吹牛获搏,可吹牛的內(nèi)容都是我干的赖条。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼常熙,長吁一口氣:“原來是場噩夢啊……” “哼纬乍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起裸卫,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤仿贬,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后墓贿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體茧泪,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年聋袋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了队伟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡幽勒,死狀恐怖嗜侮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情啥容,我是刑警寧澤锈颗,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站咪惠,受9級特大地震影響击吱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜遥昧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一覆醇、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧渠鸽,春花似錦叫乌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽革屠。三九已至凿试,卻和暖如春排宰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背那婉。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工板甘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人详炬。 一個(gè)月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓盐类,卻偏偏與公主長得像,于是被迫代替她去往敵國和親呛谜。 傳聞我的和親對象是個(gè)殘疾皇子在跳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

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