自定義視圖View繪圖基礎(chǔ)之Path的使用
使用Path繪制線
path類是一個(gè)非常有用的類,他可以預(yù)先在view上講N個(gè)點(diǎn)連成一條“路徑”,然后調(diào)用Canvas的drawPath(path,paint)即可沿著路徑繪制圖形,并且Android還為路徑提供了pathEffect來繪制效果,pathEffect包含了如下子類
-ComposePathEffect
-ComnerPathEffect
-DashPathEffect
-DiscretePathEffect
-PathDashPathEffect
-SunPathEffect
一、我們這里繪制了7條線來分別介紹上面的幾種子類都有什么用
代碼如下
運(yùn)行效果
package tester.ermu.com.canvasdemo; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ComposePathEffect; import android.graphics.CornerPathEffect; import android.graphics.DashPathEffect; import android.graphics.DiscretePathEffect; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PathDashPathEffect; import android.graphics.PathEffect; import android.graphics.SumPathEffect; import android.util.AttributeSet; import android.view.View; /** * Created by ENZ on 2016/11/17. */ public class PathText extends View { private float phase; //線條的集合, PathEffect[] effects = new PathEffect[7]; int[] colors; private Paint paint; Path path; public PathText(Context context, AttributeSet attrs) { super(context, attrs); //----------------------第一步------------------------------- //創(chuàng)建一個(gè)畫筆對象,設(shè)置畫筆類型和畫筆的大小 paint = new Paint(); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(8); //------------------------第二步----------------------------- /* 創(chuàng)建一個(gè)Path對象 * 起始點(diǎn)為moveTo(0, 0) * */ path = new Path(); path.moveTo(0, 0); //--------------------------第三步--------------------------- /* * /生成50個(gè)點(diǎn),隨機(jī)生成它們的Y坐標(biāo),并將它們連成一條Path * */ for (int i = 1; i <= 50; i++) { path.lineTo(i * 20, (float) Math.random() *100); } // 初始化7個(gè)顏色 colors = new int[] { Color.BLACK, Color.BLUE, Color.CYAN, Color.GREEN, Color.MAGENTA, Color.RED, Color.GRAY }; } public PathText(Context context){ super(context); } //-------------------------第四步---------------------------- @Override protected void onDraw(Canvas canvas){ // 將背景填充成白色 canvas.drawColor(Color.WHITE); // --------------------------------------------------- //第一條線,什么效果都不加 /* * 效果:無 * */ effects[0] = null; // --------------------------------------------------- /*第二條線 * 使用CornerPathEffect路徑效果 * 效果:拐角平滑,平滑度為10 * */ effects[1] = new CornerPathEffect(10); // --------------------------------------------------- /*第三條線 * 初始化DiscretePathEffect,使得在原來路徑的基礎(chǔ)上發(fā)生打散效果。 * 通過構(gòu)造DiscretePathEffect(float segmentLength,float deviation) * segmentLength指定最大的段長,deviation指定偏離量。 * */ effects[2] = new DiscretePathEffect(1.0f, 5.0f); // --------------------------------------------------- /*第四條線 * 初始化DashPathEffect * 這個(gè)類的作用就是將Path的線段虛線化。 * 構(gòu)造函數(shù)為DashPathEffect(float[] intervals, float offset) * 其中intervals為虛線的ON和OFF數(shù)組,該數(shù)組的length必須大于等于2,phase為繪制時(shí)的偏移量。 * */ effects[3] = new DashPathEffect(new float[] { 20, 10, 5, 10 },phase); // --------------------------------------------------- /*第五條線 * 使用Path圖形來填充當(dāng)前的路徑 * 構(gòu)造函數(shù)為PathDashPathEffect (Path shape, float advance, float phase,PathDashPathEffect.Stylestyle)。 * shape則是指填充圖形,advance指每個(gè)圖形間的間距,phase為繪制時(shí)的偏移量, * * style為該類自由的枚舉值,有三種情況:Style.ROTATE、Style.MORPH和 * ROTATE的情況下,線段連接處的圖形轉(zhuǎn)換以旋轉(zhuǎn)到與下一段移動(dòng)方向相一致的角度進(jìn)行旋轉(zhuǎn), * MORPH時(shí)圖形會(huì)以發(fā)生拉伸或壓縮等變形的情況與下一段相連接, * TRANSLATE時(shí),圖形會(huì)以位置平移的方式與下一段相連接。 * */ Path p = new Path(); p.addRect(0, 0, 8, 8, Path.Direction.CCW); effects[4] = new PathDashPathEffect(p, 12, phase,PathDashPathEffect.Style.ROTATE); // --------------------------------------------------- /*第六條線 * 這個(gè)類需要兩個(gè)PathEffect參數(shù)來構(gòu)造一個(gè)實(shí)例 * ComposePathEffect (PathEffect outerpe,PathEffect innerpe)表現(xiàn)時(shí) * 會(huì)首先將innerpe表現(xiàn)出來,然后再在innerpe的基礎(chǔ)上去增加outerpe的效果。 * * 下面我就是用了effects[2], effects[4] * */ // 初始化ComposePathEffect effects[5] = new ComposePathEffect(effects[2], effects[4]); // --------------------------------------------------- /*第七條線 * 這個(gè)類也需要兩個(gè)PathEffect作為參數(shù)SumPathEffect(PathEffect first,PathEffect second), * 但與ComposePathEffect不同的是,在表現(xiàn)時(shí),會(huì)分別對兩個(gè)參數(shù)的效果各自獨(dú)立進(jìn)行表現(xiàn),然后將兩個(gè)效果簡單的重疊在一起顯示出來。 * */ effects[6] = new SumPathEffect(effects[4], effects[3]); // --------------------------------------------------- // 將畫布移動(dòng)到(8、8)處開始繪制 canvas.translate(16, 100); // 依次使用7種不同路徑效果、7種不同的顏色來繪制路徑 for (int i = 0; i < effects.length; i++){ paint.setPathEffect(effects[i]); paint.setColor(colors[i]); canvas.drawPath(path, paint); canvas.translate(0, 160); } // 改變phase值,形成動(dòng)畫效果 // --------------------------------------------------- /* * 使用重新繪制方法invalidate();,偏移量加一,形成運(yùn)行效果 * */ phase += 1; invalidate(); } }
二、不難看出其中每條線的屬性和樣式不一樣,我在上面有 了很詳細(xì)的講解。
這里就不在介紹沒個(gè)子類的屬性了,代碼很簡單,步驟如下:
1、創(chuàng)建一個(gè)類繼承view
2、定義一個(gè)線集合,用來添加我們繪制的7跳線,通過一個(gè)for循環(huán)依次繪制
3、上面代碼中,在注釋中前四步是準(zhǔn)備工作,創(chuàng)建畫筆、設(shè)置畫布顏色、設(shè)定轉(zhuǎn)折點(diǎn)的數(shù)量及每條線的顏色
4、引用子類對象 ,來為每條線添加不同的屬性。
5、進(jìn)行繪制,并且設(shè)置偏移量加1,并且設(shè)置重繪方法,實(shí)現(xiàn)一個(gè)動(dòng)畫效果
代碼結(jié)構(gòu)視圖
三、xxxTo()方法繪制(本章延伸知識)
一、直線繪制
- 1.1 lineTo(float x, float y)
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setColor(Color.RED); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(5); // 實(shí)例化路徑 mPath = new Path(); // 連接路徑到點(diǎn)[100,100] mPath.lineTo(100, 100); // 繪制路徑 canvas.drawPath(mPath, mPaint); }
- 多次調(diào)用lineTo方法來繪制
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setColor(Color.RED); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(5); // 實(shí)例化路徑 mPath = new Path(); mPath.moveTo(100, 100); // 連接路徑到點(diǎn) mPath.lineTo(300, 100); mPath.lineTo(400, 200); mPath.lineTo(200, 200); // 繪制路徑 canvas.drawPath(mPath, mPaint); }
1.2 moveTo(float x, float y) +close()方法閉合曲線
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setColor(Color.RED); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(5); // 實(shí)例化路徑 mPath = new Path(); mPath.moveTo(100, 100); // 連接路徑到點(diǎn) mPath.lineTo(300, 100); mPath.lineTo(400, 200); mPath.lineTo(200, 200); // 閉合曲線 mPath.close(); // 繪制路徑 canvas.drawPath(mPath, mPaint); }
二、畫貝賽爾曲線
- quadTo(float x1, float y1, float x2, float y2)
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setColor(Color.RED); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(5); // 實(shí)例化路徑 mPath = new Path(); // 移動(dòng)起點(diǎn)至[100,100] mPath.moveTo(100, 100); // 連接路徑到點(diǎn) mPath.quadTo(200, 200, 300, 100); canvas.drawPath(mPath, mPaint); }
- 2.3 cubicTo(float x1, float y1, float x2, float y2, float x3, float y3)
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setColor(Color.RED); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(5); // 實(shí)例化路徑 mPath = new Path(); // 移動(dòng)起點(diǎn)至[100,100] mPath.moveTo(100, 100); // 連接路徑到點(diǎn) mPath.cubicTo(200, 200, 300, 0, 400, 100); canvas.drawPath(mPath, mPaint); }
三、畫弧線
- arcTo (RectF oval, float startAngle, float sweepAngle) 是一個(gè)畫弧線的方法,其實(shí)說白了就是從圓或橢圓上截取一部分而已。
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setColor(Color.RED); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(5); // 實(shí)例化路徑 mPath = new Path(); // 移動(dòng)起點(diǎn)至[100,100] mPath.moveTo(100, 100); // 連接路徑到點(diǎn) RectF oval = new RectF(100, 100, 200, 200); mPath.arcTo(oval, 0, 90); canvas.drawPath(mPath, mPaint); }
- arcTo (RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo) 它會(huì)強(qiáng)制起點(diǎn)為繪制的起始點(diǎn),而不是畫布的左上角。
我們來看看效果:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setColor(Color.RED); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(5); // 實(shí)例化路徑 mPath = new Path(); // 移動(dòng)起點(diǎn)至[100,100] mPath.moveTo(100, 100); // 連接路徑到點(diǎn) RectF oval = new RectF(100, 100, 200, 200); mPath.arcTo(oval, 0, 90,true); canvas.drawPath(mPath, mPaint); }
四、Path中除了上面介紹的幾個(gè)XXXTo方法外還有一套rXXXTo方法:
rCubicTo(float x1, float y1, float x2, float y2, float x3, float y3) rLineTo(float dx, float dy) rMoveTo(float dx, float dy) rQuadTo(float dx1, float dy1, float dx2, float dy2)
五、rXXXTo()方法和XXXTo()的區(qū)別
例如: 起點(diǎn)(100,100)到終點(diǎn)(200,200)
XXXTo繪制的距離就是,這里的move和lineTo的坐標(biāo)都是對于畫布左上角(0,0)來說。100到200的距離,繪制的總長度為00到200,也就是200距離
而rXXXTo繪制的距離就是相對于100起點(diǎn),再繪制200的距離。繪制的總長度就是300
- 我們寫一個(gè)例子
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setColor(Color.RED); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(5); // 實(shí)例化路徑 mPath = new Path(); // 移動(dòng)點(diǎn)至[100,100] mPath.moveTo(100, 100); // 連接路徑到點(diǎn) mPath.lineTo(200, 200); canvas.drawPath(mPath, mPaint); }
這里的move和lineTo的坐標(biāo)都是對于畫布左上角(0,0)來說的,是一個(gè)絕對坐標(biāo)。而我們換為mPath.rLineTo(200, 200); 后呢?
是不是感覺線段長了很多,因?yàn)檫@里的(200,200)是相對于開始點(diǎn)(100,100)來說的,是相對坐標(biāo)。如果換算成絕對坐標(biāo)就是繪制一條(100,100)到(300,300)之間的線段。
其實(shí),這個(gè)前綴“r”也就是relative(相對)的簡寫!
六、addXXX方法
XXXTo方法可以連接Path中的曲線,而Path提供的另一系列addXXX方法則可以讓我們直接往Path中添加一些曲線,比如
- addArc(RectF oval, float startAngle, float sweepAngle) : 它允許我們將一段弧形添加至Path,注意這里我用到了“添加”這個(gè)詞匯,
也就是說,通過addXXX方法添加到Path中的曲線是不會(huì)和上一次的曲線進(jìn)行連接的:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setColor(Color.RED); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(5); // 實(shí)例化路徑 mPath = new Path(); // 移動(dòng)點(diǎn)至[100,100] mPath.moveTo(100, 100); // 連接路徑到點(diǎn) mPath.lineTo(200, 200); // 添加一條弧線到Path中 RectF oval = new RectF(100, 100, 300, 400); mPath.addArc(oval, 0, 90); canvas.drawPath(mPath, mPaint); }
如圖和代碼所示,雖然我們先繪制了由[100,100]到[200,200]的線段,但是在我們往Path中添加了一條弧線后該弧線并沒與線段連接。
除了addArc,Path還提供了一系列的add方法:
addCircle(float x, float y, float radius, Path.Direction dir)
addOval(float left, float top, float right, float bottom, Path.Direction dir)
addRect(float left, float top, float right, float bottom, Path.Direction dir)
addRoundRect(float left, float top, float right, float bottom, float rx, float ry, Path.Direction dir)
這些方法和addArc有很明顯的區(qū)別,就是多了一個(gè)Path.Direction參數(shù),其他呢都大同小異,除此之外不知道大家還發(fā)現(xiàn)沒有,addArc是往Path中添加一段弧,說白了就是一條開放的曲線,而上述幾種方法都是一個(gè)具體的圖形,或者說是一條閉合的曲線,Path.Direction的意思就是標(biāo)識這些閉合曲線的閉合方向。Path.Direction只有兩個(gè)常量值CCW和CW分別表示逆時(shí)針方向閉合和順時(shí)針方向閉合。
例如順時(shí)針方向閉合
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setColor(Color.RED); mPaint.setStyle(Paint.Style.STROKE); // 實(shí)例化路徑 mPath = new Path(); // 移動(dòng)起點(diǎn)至[100,100] mPath.moveTo(100, 100); // 添加一條弧線到Path中 RectF oval = new RectF(100, 100, 300, 400); mPath.addOval(oval, Path.Direction.CW); canvas.drawPath(mPath, mPaint); mPaint.setTextSize(50); // 繪制路徑上的文字 canvas.drawTextOnPath("123456789", mPath, 0, 0, mPaint); }
如果我們換作:mPath.addOval(oval, Path.Direction.CCW);
- 逆時(shí)針封閉
到此這篇關(guān)于自定義視圖View繪圖基礎(chǔ)之Path的使用的文章就介紹到這了,更多相關(guān)自定義視圖Path使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android仿微信頁面底部導(dǎo)航效果代碼實(shí)現(xiàn)
本文給大家分享一段代碼有關(guān)android仿微信頁面底部導(dǎo)航效果代碼實(shí)現(xiàn)的思路,非常不錯(cuò),感興趣的朋友一起看看吧2016-09-09Android實(shí)現(xiàn)圖片輪播切換實(shí)例代碼
利用Android的ViewFlipper和AnimationUtils實(shí)現(xiàn)圖片帶有動(dòng)畫的輪播切換,其中當(dāng)點(diǎn)擊“上一張”圖片時(shí),切換到上一張圖片;當(dāng)點(diǎn)擊“下一張”圖片時(shí),切換到下一張圖片,本文給大家介紹Android實(shí)現(xiàn)圖片輪播切換實(shí)例代碼,需要的朋友參考下2015-12-12Android6.0編程實(shí)現(xiàn)雙向通話自動(dòng)錄音功能的方法詳解
這篇文章主要介紹了Android6.0編程實(shí)現(xiàn)雙向通話自動(dòng)錄音功能的方法,結(jié)合實(shí)例形式分析了Android錄音功能的原理、實(shí)現(xiàn)技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-07-07Android自定義PopWindow帶動(dòng)畫向下彈出效果
這篇文章主要為大家詳細(xì)介紹了Android自定義PopWindow帶動(dòng)畫向下彈出效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11Flutter 狀態(tài)管理的實(shí)現(xiàn)
這篇文章主要介紹了Flutter 狀態(tài)管理的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06Android顯示系統(tǒng)SurfaceFlinger詳解
本文詳細(xì)講解了Android顯示系統(tǒng)SurfaceFlinger,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-12-12Android IPC進(jìn)程間通信詳解最新AndroidStudio的AIDL操作)
這篇文章主要介紹了Android IPC進(jìn)程間通信的相關(guān)資料,需要的朋友可以參考下2016-09-09Flutter沉浸式狀態(tài)欄/AppBar導(dǎo)航欄/仿咸魚底部凸起導(dǎo)航欄效果
這篇文章主要介紹了Flutter沉浸式狀態(tài)欄/AppBar導(dǎo)航欄/仿咸魚底部凸起導(dǎo)航欄效果,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04