Android動(dòng)畫 - PathMeasure打造不一樣的動(dòng)畫

Android動(dòng)畫 - PathMeasure打造不一樣的動(dòng)畫

PathMeasures是什么

顧名思義,PathMeasure是一個(gè)用來測(cè)量Path的類

構(gòu)造函數(shù)

構(gòu)造函數(shù) 方法描述
PathMeasure() 創(chuàng)建一個(gè)空的PathMeasure對(duì)象。
PathMeasure(Path path, boolean forceClosed) 創(chuàng)建與指定路徑對(duì)象(已經(jīng)創(chuàng)建并指定)關(guān)聯(lián)的PathMeasure對(duì)象。

公共方法

返回值 方法名稱
float getLength()
boolean getMatrix(float distance, Matrix matrix, int flags)
boolean getPosTan(float distance, float[] pos, float[] tan)
boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo)
boolean isClosed()
boolean nextContour()
void setPath(Path path, boolean forceClosed)

接下來分別介紹下以上的方法


1.構(gòu)造函數(shù)

無參構(gòu)造函數(shù):
PathMeasure()

創(chuàng)建一個(gè)空的PathMeasure,要使用它來測(cè)量路徑長(zhǎng)度,或查找路徑的位置和切線,需要調(diào)用setPath。一旦路徑與測(cè)量對(duì)象相關(guān)聯(lián),Path進(jìn)行了更改,需要重新調(diào)用setPath方法。

有參構(gòu)造函數(shù)
PathMeasure(Path path, boolean forceClosed)

創(chuàng)建與指定路徑對(duì)象關(guān)聯(lián)的PathMeasure對(duì)象。現(xiàn)在,測(cè)量對(duì)象可以返回路徑的長(zhǎng)度以及路徑上任何位置的位置和切線。同上,一旦路徑與測(cè)量對(duì)象相關(guān)聯(lián),Path進(jìn)行了更改,需要重新調(diào)用setPath方法。
forceClosed:如果為true,該路徑也將被視為“閉合”。

forceClosed不會(huì)影響Path本身的狀態(tài)。但是會(huì)影響測(cè)量結(jié)果。

下面我們舉個(gè)例子:

    canvas.translate(mWidth/2,mHeight/2);

    Path path = new Path();
    path.lineTo(0,200);
    path.lineTo(200,200);
    path.lineTo(200,0);
    PathMeasure measure1 = new PathMeasure(path,false);
    PathMeasure measure2 = new PathMeasure(path,true);

    Log.e("TAG", "forceClosed=false---->"+measure1.getLength());
    Log.e("TAG", "forceClosed=true----->"+measure2.getLength());
    canvas.drawPath(path,mDeafultPaint);

log如下:

E/TAG: forceClosed=false---->600.0
E/TAG: forceClosed=true----->800.0

繪制的效果如下:


4041603852675_.pic_thumb.jpg

2.公共方法

getLength

返回當(dāng)前Path的總長(zhǎng)度;如果沒有路徑與此度量對(duì)象關(guān)聯(lián),則返回0。

isClosed

如果當(dāng)前Path為close(),則返回true。

setPath

Path與PathMeasure進(jìn)行關(guān)聯(lián)。
主要講一下以下幾個(gè)方法:

nextContour

public boolean nextContour()

獲取在路徑中下一個(gè)輪廓,如果有下一個(gè)輪廓,則返回true,且PathMeasure切至下一個(gè)輪廓的數(shù)據(jù);如果沒有下一個(gè)輪廓?jiǎng)t返回false。
我的理解一次moveTo增加一個(gè)輪廓。

getSegment
public boolean getSegment(float startD,float stopD,Path dst,boolean startWithMoveTo)

給定起點(diǎn)和終點(diǎn)的距離,請(qǐng)返回中間的路段。如果段的長(zhǎng)度為零,則返回false,否則返回true。startD和stopD固定取值范圍(0,getLength())。如果startD> = stopD,則返回false(并保持dst不變)。如果startWithMoveTo為true,則以moveTo開頭。

參數(shù) 作用
startD 開始截取的位置距離Path起點(diǎn)的距離
stopD 結(jié)束截取的位置距離Path起點(diǎn)的距離
dst 截取的Path會(huì)添加到dst中
startWithMoveTo 起點(diǎn)是否啟用moveTo

startD 和 stopD 的取值范圍 0 <= startD < stopD <= getLength
startWithMoveTo: 截取的片段的第一個(gè)點(diǎn)是否保持不變;
設(shè)置為true:保持截取的片段不變,添加至dst路徑中;
設(shè)置為false:會(huì)將截取的片段的起始點(diǎn)移至dst路徑中的最后一個(gè)點(diǎn),讓dst路徑保持連續(xù)

舉個(gè)例子:startWithMoveTo 為flase

canvas.translate(width/2,height/2);
Path mPath = new Path();
Path mDst = new Path();
PathMeasure mPathMeasure = new PathMeasure();
// 順時(shí)針畫 半徑為400px的圓
mPath.addCircle(0,0, 400, Path.Direction.CW);
mPathMeasure.setPath(mPath, false);

// 畫直線
mDst.moveTo(110, 0);
mDst.lineTo(200, 300);

// 截取 0.25 到 0.5 距離的圓弧放置dst中
mPathMeasure.getSegment(mPathMeasure.getLength() * 0.25f,
                mPathMeasure.getLength() * 0.5f,
                mDst,
                false);

canvas.drawPath(mDst, paint);

效果圖如下:


4011603795757_.pic_thumb.jpg

startWithMoveTo 為true
效果圖如下:


4021603795817_.pic_thumb.jpg
getPosTan
public boolean getPosTan(float distance, float pos[], float tan[]) 
參數(shù) 作用
distance 即需要的測(cè)量點(diǎn)與當(dāng)前path起始位置的距離
pos 測(cè)量點(diǎn)的坐標(biāo),pos[0]為x坐標(biāo),pos[1]為y坐標(biāo)
tan 測(cè)量點(diǎn)的正余弦值,tan[0]為cos,即余弦值或稱為單位圓的x坐標(biāo);tan[1]為sin,即正弦值或稱為單位圓的y坐標(biāo);

distance 取值范圍:0<=distance<=getLength()
A(x,y)原點(diǎn)為O,cos = OA/OB,sin = OA/AB

getMatrix

public boolean getMatrix(float distance, Matrix matrix, int flags)
參數(shù) 作用
distance 即需要的測(cè)量點(diǎn)與當(dāng)前path起始位置的距離
matrix 根據(jù) falgs 封裝好的matrix
flags 規(guī)定哪些內(nèi)容會(huì)存入到matrix中

flags 有POSITION_MATRIX_FLAG(位置) 和 ANGENT_MATRIX_FLAG(正切)兩種
其實(shí)這個(gè)方法就相當(dāng)于getPosTan的封裝 matrix 的過程由 getMatrix 替我們做了,我們可以直接得到一個(gè)封裝好到 matrix。

實(shí)戰(zhàn)

加載動(dòng)畫(一)

效果圖

LoadingCircleView.gif

主要利用PathMeasure的getSegment方法來截取路徑,繪制該動(dòng)畫

思路

1.先勾勒出一個(gè)順時(shí)針的空心圓,然后生成pathMeasure對(duì)象

// 勾勒空心圓
path.addCircle(width / 2, height / 2, radius, Path.Direction.CW);
// 生成pathMeasure對(duì)象
pathMeasure.setPath(path, true);

2.截取的開始值和結(jié)束值

stop = mAnimatorValue * mLength;
start = (float) (stop - ((0.5 - Math.abs(mAnimatorValue - 0.5)) * mLength));

mAnimatorValue 的取值為(0,1) ,當(dāng)mAnimatorValue為0或1時(shí),兩個(gè)值相等。

3.截取路徑后繪制路徑

pathMeasure.getSegment(start, stop, dst, true);
canvas.drawPath(dst, paint);

完整代碼地址:
有用記得點(diǎn)顆小星星


加載動(dòng)畫化(二)

效果圖

LoadingArrowView.gif

思路

主要利用getPosTan 獲取測(cè)量點(diǎn)的坐標(biāo)和正余弦值,控制箭頭的方法和位置
1.先勾勒出一個(gè)順時(shí)針的空心圓,然后生成pathMeasure對(duì)象

// 勾勒空心圓
path.addCircle(width / 2, height / 2, radius, Path.Direction.CW);
// 生成pathMeasure對(duì)象
pathMeasure.setPath(path, true);

2.獲取繪制點(diǎn)的測(cè)量坐標(biāo)和正余弦值,根據(jù)tan[0],tan[1]來計(jì)算箭頭旋轉(zhuǎn)的角度。

measure.getPosTan(measure.getLength() * mAnimatorValue, pos, tan);
float angle = (float) (Math.atan2(tan[1], tan[0]) * 180 / Math.PI);

mAnimatorValue 的取值為(0,1) ,當(dāng)mAnimatorValue為0或1時(shí),兩個(gè)值相等。
angle計(jì)算方式自行查找,數(shù)學(xué)知識(shí)。

3.用Matrix對(duì)bitmap進(jìn)行旋轉(zhuǎn)和平移

mMatrix.postRotate(angle,mBitmap.getWidth()/2,mBitmap.getHeight()/2);
mMatrix.postTranslate(pos[0] - mBitmap.getWidth() / 2,pos[1] - mBitmap.getHeight() / 2);

4.繪制bitmap

canvas.drawBitmap(mBitmap,mMatrix,mPaint);

完整代碼地址:
有用記得點(diǎn)顆小星星


往期文章地址

Android動(dòng)畫 - 仿花束直播加載動(dòng)畫
Android動(dòng)畫 - 仿58同城加載動(dòng)畫
Android動(dòng)畫 - 仿抖音加載動(dòng)畫

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容