PathMeasure
作用:測(cè)量并獲取Path的信息,用于繪制Path路徑實(shí)現(xiàn)動(dòng)畫(huà)效果
ValueAnimator在這里不會(huì)講解,不過(guò)至關(guān)重要,是動(dòng)畫(huà)的發(fā)動(dòng)機(jī)!
基本路徑繪制
預(yù)覽:

普通路徑繪制.mp4_1491231595.gif
- 生成完整的目標(biāo)路徑
- 初始化PathMeasure對(duì)象
-
PathMeasure.setPath(targetPath,true)測(cè)量路徑 -
mPathMeasure.getLength();獲取路徑的總長(zhǎng)度 - 初始化動(dòng)態(tài)的路徑
mDstPath -
mPathMeasure.getSegment(startD, stopD, mDstPath, true);: 根據(jù)傳入的起始值和終止值(相當(dāng)于要截取路徑的部分),將路徑賦值給mDstPath - 使用ValueAnimator產(chǎn)生一個(gè)增長(zhǎng)值來(lái)控制 終止值 如:
float stopD = mAnimatedValue * mLength; - 最后將
mDstPath繪制出來(lái),就可以實(shí)現(xiàn)路徑的逐步繪制效果了
//完整的圓的路徑
mCirclePath = new Path();
//路徑繪制每段截取出來(lái)的路徑
mDstPath = new Path();
mCirclePath.addCircle(0, 0, 200, Path.Direction.CW);
//路徑測(cè)量類(lèi)
mPathMeasure = new PathMeasure();
//測(cè)量路徑
mPathMeasure.setPath(mCirclePath, true);
//獲取被測(cè)量路徑的總長(zhǎng)度
mLength = mPathMeasure.getLength();
mValueAnimator = ValueAnimator.ofFloat(0, 1);
mValueAnimator.setDuration(2000);
mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
mValueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//獲取從0-1的變化值
mAnimatedValue = (float) animation.getAnimatedValue();
//不斷刷新繪圖,實(shí)現(xiàn)路徑繪制
invalidate();
}
});
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//必須要有l(wèi)ineTo(0,0)才可以實(shí)現(xiàn)路徑的完整繪制
mDstPath.reset();
mDstPath.lineTo(0, 0);
float stopD = mAnimatedValue * mLength;
float startD = 0;
//獲取當(dāng)前進(jìn)度的路徑,同時(shí)賦值給傳入的mDstPath
mPathMeasure.getSegment(startD, stopD, mDstPath, true);
canvas.save();
canvas.translate(300, 300);
canvas.drawPath(mDstPath, mPaint);
canvas.restore();
}
Windows風(fēng)格加載動(dòng)畫(huà)繪制
預(yù)覽:

windows路徑繪制.mp4_1491231732.gif
- 實(shí)現(xiàn)這種效果只要在上面的基礎(chǔ)上動(dòng)態(tài)改變我們所截取的
startD就可以了
只要加上這一句代碼
//通過(guò)設(shè)置其實(shí)位置的變化來(lái)實(shí)現(xiàn)Window加載風(fēng)格
startD = (float) (stopD - ((0.5 - Math.abs(mAnimatedValue - 0.5)) * mLength));
獲取路徑點(diǎn)的坐標(biāo)和角度
預(yù)覽:

箭頭路徑繪制.mp4_1491231817.gif
主要涉及mPathMeasure.getPosTan(float distance, float pos[], float tan[]) 這個(gè)API
-
distance: 這個(gè)參數(shù)就是確定要獲取路徑上那個(gè)位置的點(diǎn) -
pos[]: 根據(jù)distance返回 點(diǎn)的坐標(biāo)信息并保存在傳入的pos[]內(nèi), X保存在pos[0], Y則在pos[1] -
tan[]: 根據(jù)distance返回 點(diǎn)的角度信息并保存?zhèn)魅雝an[]內(nèi) ,主要結(jié)合float degree = (float) (Math.atan2(mTan[1], mTan[0]) * 180 / Math.PI);
這個(gè)公式 就可以求得當(dāng)前點(diǎn)的切線和X正半軸的角度
具體繪制:
if (mIsArrow) {
//mPos是當(dāng)前路徑點(diǎn)的坐標(biāo)
//mTan通過(guò)下面公式可以得到當(dāng)前點(diǎn)的切線角度
mPathMeasure.getPosTan(mAnimatedValue * mLength, mPos, mTan);
float degree = (float) (Math.atan2(mTan[1], mTan[0]) * 180 / Math.PI);
Log.e("lzh", "onDraw: degree=" + degree);
canvas.save();
canvas.translate(300, 300);
canvas.drawCircle(mPos[0], mPos[1], 10, mPaint);
canvas.rotate(degree);
//繪制切線
canvas.drawLine(0, -200, 200, -200, mPaint);
canvas.restore();
}
最后:
PathMeasure大大簡(jiǎn)化了我們?nèi)?shí)現(xiàn)一個(gè)復(fù)雜路徑的成本,只需要繪制好一個(gè)Path,剩下的就都交給PathMeasure搞定!
當(dāng)然,其實(shí)動(dòng)畫(huà)本身最可貴的還是源于一個(gè)好的想法。
如果覺(jué)有有用,可以點(diǎn)贊鼓勵(lì)一下哈O(∩_∩)O~~
附上:代碼Github