View详解(4)
在上文中我們簡(jiǎn)單介紹了Canvas#drawCircle()的使用方式,以及Paint#setStyle(),Paint#setStrokeWidth(),Paint#setColor()等相關(guān)函數(shù),不知道小伙伴們了解了多少?那么是不是所有的圖形都能通過圓來描述呢?當(dāng)然不行,那么熟悉API套路的我們就應(yīng)該知道,這時(shí)候應(yīng)該去看Canvas源碼中提供的公有方法是否能滿足我們的需求,這樣我們就會(huì)看到下表中的公有函數(shù):
| drawBitmap | 繪制圖片 |
| drawArc | 繪制圓弧 |
| drawLine | 繪制線條 |
| drawOval | 繪制橢圓 |
| drawPoint | 繪制點(diǎn) |
| drawRect | 繪制矩形 |
| drawRoundRect | 繪制圓角矩形 |
| drawText | 繪制字符串 |
上表中大多數(shù)函數(shù)都不止一個(gè)實(shí)現(xiàn),具體的參數(shù)含義也不同。激動(dòng)的你們是不是已經(jīng)搬好小板凳,等著我講解這些函數(shù)的用法及參數(shù)了?不好意思,要讓你們失望了,我一向秉承,授之以魚,不如授之以漁,所以親們自行嘗試這些函數(shù)哦,繪制結(jié)果老規(guī)矩,后臺(tái)等你們哦!
接下來敲黑板,開始畫重點(diǎn)嘍,仔細(xì)排查上表中函數(shù),思考三角形,五角形,六角形,五角星等的繪制方法??隙ㄓ行』锇榱⒖萄a(bǔ)刀,傻不傻?畫線啊,拼起來不就好?那么問題來了,讓你畫一個(gè)紅色三角形怎么搞?三條線拼起來,Paint設(shè)置成Style.FILL能搞定?
機(jī)智的我立馬去擼了一波代碼
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawLine(10,10,200,200,mPaint); canvas.drawLine(200,200,150,200,mPaint); canvas.drawLine(150,200,10,10,mPaint); } private void init(){ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setColor(Color.RED); mPaint.setStyle(Style.FILL); }復(fù)制代碼手抖一運(yùn)行,秒打臉,結(jié)果是圖-錯(cuò)誤的三角
那到底要怎么整呢?Google爸爸設(shè)計(jì)API不可能沒考慮到這些東東啊?不服氣,接著搜源碼,終于找到了一個(gè)看不懂的東東:public void drawPath(@NonNull Path path, @NonNull Paint paint)復(fù)制代碼
這個(gè)Path到底是個(gè)什么東東,下面我們一起來學(xué)習(xí)下。
Path
什么是Path
Path英翻漢的結(jié)果是路徑,路途,也就是說Path代表著一段可用路徑。使用Path可以構(gòu)建一個(gè)路徑對(duì)象,用于Canvas繪制,Path中的相關(guān)函數(shù)及說明我們用到一個(gè)講解一個(gè),有興趣的小伙伴可以自行查閱嘗試,資料很多。
繪制三角形
在使用Path定義路徑時(shí),我們首先應(yīng)該為該路徑指定起點(diǎn),使用Path#moveTo()方法,隨后使用其他函數(shù)繪制所需路徑即可,以開篇三角形為例,構(gòu)建Path的代碼如下:
//Path對(duì)象初始化 mPath = new Path(); //移動(dòng)路徑起點(diǎn)到(10,10) mPath.moveTo(10,10); //從點(diǎn)(10,10)繪制直線到點(diǎn)(200,200) mPath.lineTo(200,200); //從點(diǎn)(200,200)繪制直線到點(diǎn)(150,200) mPath.lineTo(150,200); //閉合該路徑,從當(dāng)前點(diǎn)繪制直線到起點(diǎn) mPath.close();復(fù)制代碼隨后使用Canvas#drawPath繪制該路徑,代碼如下:
//第一個(gè)參數(shù)為路徑對(duì)象,第二個(gè)參數(shù)為畫筆canvas.drawPath(mPath,mPaint);復(fù)制代碼再次運(yùn)行,我們可以看到界面上有一個(gè)實(shí)心紅色三角形,如下圖:
這里請(qǐng)大家自行繪制五邊形,六邊形。老規(guī)矩,截圖甩后臺(tái)。
前面小試牛刀,繪制了一個(gè)小小三角形,大家對(duì)Path應(yīng)該還是一知半解,接下來我們進(jìn)一步學(xué)習(xí)如何使用Path描述自定義View中的不規(guī)則路徑。目標(biāo)下面動(dòng)圖:
咋一看,是不是一個(gè)頭兩個(gè)大,不要方,都是紙老虎,我們來一點(diǎn)一點(diǎn)分析。
動(dòng)畫形成過程
仔細(xì)觀察上面動(dòng)圖,我們不難發(fā)現(xiàn)整個(gè)圖形由四部分組成,拿出其中一部分單獨(dú)分析,我們不難得到下圖:
左上角這四分之一是由兩條直線加四分之一圓弧組成,其中動(dòng)畫是由點(diǎn)P的位置變化形成的,P點(diǎn)坐標(biāo)范圍起于圖1止于圖4.
Path組成及點(diǎn)坐標(biāo)
還是以左上角四分之一做細(xì)致分析,講解Path的形成過程及點(diǎn)坐標(biāo),詳細(xì)的左上角坐標(biāo)標(biāo)記如下圖:
描述左上角的Path路徑對(duì)象偽代碼如下:
移動(dòng)起點(diǎn)到點(diǎn)B,繪制四分之一圓,繪制直線AP,然后閉合該路徑即可復(fù)制代碼進(jìn)一步細(xì)化上圖中輔助點(diǎn),計(jì)算我們所需要的三個(gè)關(guān)鍵點(diǎn)P,A,B的坐標(biāo),細(xì)化后的分析圖如下:
如上圖所示我們假設(shè)要繪制的圓半徑為R,那么可以得到P點(diǎn)所能取得的最大坐標(biāo)值為(O-B1,O-A1),其中O-B1=O-A1。
由于三角形OPA是等腰三角形,所以其高線P-A1=R/2,又B1-O = P-A1,所以O(shè)-B1 = R/2
進(jìn)而我們可以得到P點(diǎn)的取值范圍為(0,0)到(R/2,R/2).
生成Path
切換坐標(biāo)系到我們的View坐標(biāo)系內(nèi),假設(shè)P點(diǎn)坐標(biāo)為(x,x),x取值范圍為0到R/2,從而我們可以確認(rèn)得到左上角路徑上的P,A,B三點(diǎn)坐標(biāo),其中:
A(mWidth/2,mHeight/2 - R)
B(mWidth/2 - R,mHeight/2)
P(mWidth/2 - x,mHeight/2 - x)
獲得ABP三點(diǎn)坐標(biāo)后,接下來的重點(diǎn)就是怎么將四分之圓加入Path對(duì)象了,這里我們就需要用到Path#addArc()方法了,函數(shù)聲明如下:
//第一個(gè)參數(shù)為圓弧所在矩形區(qū)域,第二個(gè)參數(shù)為截圖的開始角度,第三個(gè)參數(shù)為截取的角度大小public void addArc(RectF oval, float startAngle, float sweepAngle)復(fù)制代碼畫圖說明如下:
一點(diǎn)要注意第三個(gè)參數(shù)是截取得角度大小,從水平方向開始,順時(shí)針取正值,逆時(shí)針取負(fù)值
那么此時(shí)我們就可以確定左上角的Path對(duì)象了,代碼如下:
//清空上一次Path中存放的所有路徑 mPath3.reset(); //移動(dòng)路徑起點(diǎn)到B點(diǎn) mPath3.moveTo(mWidth / 2 - mRadius, mHeight / 2); //繪制四分之一圓弧BA mPath3.addArc(new RectF(mWidth / 2 - mRadius, mHeight / 2 - mRadius, mWidth / 2 + mRadius, mHeight / 2 + mRadius), 180, 90); //繪制直線AP mPath3.lineTo(mWidth / 2 - x, mHeight / 2 - x); //閉合曲線,默認(rèn)繪制直線PB mPath3.close();復(fù)制代碼生成動(dòng)畫
public void startAnimation() { //新建ValueAnimator對(duì)象 mValueAnimator = ValueAnimator.ofFloat(0f, mRadius / 2f); //設(shè)置動(dòng)畫單次時(shí)長(zhǎng) mValueAnimator.setDuration(5000); //設(shè)置動(dòng)畫重復(fù)模式,REVERSE--反轉(zhuǎn),RESTART--重新開始 mValueAnimator.setRepeatMode(ValueAnimator.REVERSE); //設(shè)置動(dòng)畫重復(fù)次數(shù),-1 --- INFINE mValueAnimator.setRepeatCount(-1); mValueAnimator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { //更新P點(diǎn)坐標(biāo) x = (float) valueAnimator.getAnimatedValue(); postInvalidate(); } }); mValueAnimator.start(); }復(fù)制代碼運(yùn)行后效果如下:
作業(yè)
上面已經(jīng)詳細(xì)解釋了左上角的繪制過程,相信機(jī)智的你已經(jīng)完全懂了,那么請(qǐng)自行完成剩余三部分的繪制,交流群里gif甩起來。
下期預(yù)告
提前透漏個(gè)動(dòng)畫給你們。還是在圓上搞事情,感覺和圓杠上了。
完整代碼
public class ArcView extends View { private Paint mPathPaint; private Path mPath; private int mWidth; private int mHeight; private int mRadius = 200; private ValueAnimator mValueAnimator; private float x = 0f; public ArcView(Context context) { super(context); init(); } public ArcView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); if (w > 0 && h > 0) { mWidth = w; mHeight = h; } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); initPaths(); mPathPaint.setColor(Color.parseColor("#FD9A59")); canvas.drawPath(mPath, mPathPaint); } private void init() { mPathPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPathPaint.setStyle(Style.FILL); mPath = new Path(); } private void initPaths() { mPath.reset(); mPath.moveTo(mWidth / 2 - mRadius, mHeight / 2); mPath.addArc(new RectF(mWidth / 2 - mRadius, mHeight / 2 - mRadius, mWidth / 2 + mRadius, mHeight / 2 + mRadius), 180, 90); mPath.lineTo(mWidth / 2 - x, mHeight / 2 - x); mPath.close(); } public void startAnimation() { mValueAnimator = ValueAnimator.ofFloat(0f, mRadius / 2f); mValueAnimator.setDuration(5000); mValueAnimator.setRepeatMode(ValueAnimator.REVERSE); mValueAnimator.setRepeatCount(-1); mValueAnimator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { x = (float) valueAnimator.getAnimatedValue(); postInvalidate(); } }); mValueAnimator.start(); }}復(fù)制代碼覺得不錯(cuò)的親們動(dòng)動(dòng)手指分享轉(zhuǎn)發(fā)下哈。
轉(zhuǎn)載于:https://juejin.im/post/5bc85103e51d450e925290d3
總結(jié)
- 上一篇: MP实战系列(十七)之乐观锁插件
- 下一篇: 梦到蛇在水里游预示着什么