日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

自定义View中Canvas之Path的详解

發(fā)布時(shí)間:2023/12/18 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 自定义View中Canvas之Path的详解 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

上一篇Canvas的繪制圖形只能繪制一些常規(guī)的,比如點(diǎn)、線、圓、橢圓、矩形等的。如果想要繪制更復(fù)雜的圖形,那么就得靠Path了。

Path的定義:
Path類將多種符合路徑(多個(gè)輪廓,如直線段、二次曲線、立方曲線等)封裝在其內(nèi)部的幾何路徑。

Path的繪制:
通過設(shè)置Paint.Style的FILL(只描內(nèi)容)、STROKE(只描邊)、FILL_AND_STROKE(描邊和內(nèi)容),然后調(diào)用canvas.drawPath(path, paint);Path還可以用于剪切或者在路徑上繪制文本canvas.drawTextOnPath()。

Path有兩個(gè)構(gòu)造函數(shù)

Path() // 空的構(gòu)造函數(shù) Path(Path src) //創(chuàng)建一個(gè)新的路徑,并且從src路徑里賦值內(nèi)容

Path一些常用的API:

功能分類Path的常用API備注
線操作lineTo、rLineTo繪制線
點(diǎn)操作 moveTo、rMoveTo 改變后面操作的起始點(diǎn)位置 setLastPoint 改變前面操作中最后點(diǎn)的位置 常規(guī)圖形操作 addRect 繪制矩形 addRoundRect 繪制圓角矩形 addCircle 繪制圓 addOval 繪制橢圓 addArc、arcTo 繪制圓弧 閉合path操作 close 如果連接Path起點(diǎn)和終點(diǎn)能形成一個(gè)閉合圖形,則會(huì)將起點(diǎn)和終點(diǎn)連接起來形成一個(gè)閉合圖形 貝塞爾曲線 quadTo、rQuadTo、cubicTo、rCubicTo 貝塞爾曲線

###線操作 lineTo(float x, float y) //添加當(dāng)前點(diǎn)到目標(biāo)點(diǎn)(x,y)構(gòu)成的直線到path rLineTo(float dx, float dy) //基于當(dāng)前坐標(biāo)系,即以path最后的那個(gè)點(diǎn) //為坐標(biāo)系原點(diǎn)(0,0),如果前面沒有path的點(diǎn),默認(rèn)是屏幕左上角(0,0)

注:lineTo、rLineTo起始點(diǎn)默認(rèn)是屏幕左上角的坐標(biāo)系原點(diǎn)(0,0)

演示一下:

Paint paint = new Paint();paint.setStyle(Paint.Style.STROKE); //只描邊paint.setColor(Color.BLUE);paint.setStrokeWidth(10f);paint.setAntiAlias(true); //設(shè)置抗鋸齒paint.setDither(true); //設(shè)置防抖動(dòng)Path path = new Path();//屏幕左上角(0,0)到(200,200)畫一條直線path.lineTo(200, 200);//(200, 200)到(200, 400)畫一條直線path.lineTo(200, 400);//以(200, 400)為起始點(diǎn)(0,0)偏移量為(200, 400)畫一條直線,//其終點(diǎn)坐標(biāo)實(shí)際在屏幕的位置為(400, 800)path.rLineTo(400, 800);canvas.drawPath(path, paint);

結(jié)果:



點(diǎn)操作

moveTo(float x, float y) //改變接下來操作的起點(diǎn)位置為(x,y) rMoveTo(float dx, float dy) //接下來要操作的起點(diǎn)位置為(x+dx,y+dy) setLastPoint(float dx, float dy) //改變前一步操作點(diǎn)的位置,會(huì)改變前一步的操作

先對比一下moveTo()和rMoveTo()的區(qū)別,演示一下:

Paint paint = new Paint();paint.setStyle(Paint.Style.STROKE); //只描邊paint.setColor(Color.BLUE);paint.setStrokeWidth(10f);paint.setAntiAlias(true); //設(shè)置抗鋸齒paint.setDither(true); //設(shè)置防抖動(dòng)Path path = new Path();//將坐標(biāo)系原點(diǎn)從(0,0)移動(dòng)到(200,200)path.moveTo(200,200);//畫從(200,200)到(400,400)之間的直線path.lineTo(400, 400); // path.rMoveTo(100, 0); //暫時(shí)注釋path.lineTo(800, 400);canvas.drawPath(path, paint);

暫時(shí)注釋了rMoveTo()方法,看看結(jié)果:

然后解掉rMoveTo()方法的注釋,意思是下一步的起點(diǎn)位置由(400, 400)變?yōu)?400+100, 400+0),即(500,400),結(jié)果:

再來看看moveTo()和setLastPoint()的區(qū)別,同樣以上的代碼,加上path.setLastPoint(800, 200)方法:

Paint paint = new Paint();paint.setStyle(Paint.Style.STROKE); //只描邊paint.setColor(Color.BLUE);paint.setStrokeWidth(10f);paint.setAntiAlias(true); //設(shè)置抗鋸齒paint.setDither(true); //設(shè)置防抖動(dòng)Path path = new Path();//將坐標(biāo)系原點(diǎn)從(0,0)移動(dòng)到(200,200)path.moveTo(200,200);//畫從(200,200)到(400,400)之間的直線path.lineTo(400, 400);path.setLastPoint(800, 200);path.lineTo(800, 400);canvas.drawPath(path, paint);

結(jié)果:

紅線原本是設(shè)置setLastPoint(800, 200)之前的路徑,在設(shè)置之后,影響到了前一步lineTo(400, 400)的操作,使之變成了lineTo(800, 200),結(jié)果就如圖了。

得出結(jié)論: rMoveTo()影響的是后面操作的起點(diǎn)位置,并不會(huì)影響之前的操作;而setLastPoint()改變前一步操作最后一個(gè)點(diǎn)的位置,不僅影響前一步操作,同時(shí)也會(huì)影響后一步操作。



### 繪制常規(guī)圖形 //繪制圓 addCircle(float x, float y, float radius, Direction dir) //繪制橢圓 addOval(RectF oval, Direction dir) addOval(float left, float top, float right, float bottom, Direction dir) //繪制矩形 addRect(RectF rect, Direction dir) addRect(float left, float top, float right, float bottom, Direction dir) //繪制圓角矩形 addRoundRect(RectF rect, float rx, float ry, Direction dir) addRoundRect(float left, float top, float right, float bottom, float rx, float ry,Direction dir) addRoundRect(RectF rect, float[] radii, Direction dir) addRoundRect(float left, float top, float right, float bottom, float[] radii,Direction dir)

所有API里面都有一個(gè)共同的參數(shù)Direction

Direction備注
Path.Direction.CCWcounter-clockwise ,沿逆時(shí)針方向繪制
Path.Direction.CWclockwise ,沿順時(shí)針方向繪制

Direction其用法演示:

Paint paint = new Paint();paint.setStyle(Paint.Style.STROKE); //只描邊paint.setColor(Color.BLUE);paint.setStrokeWidth(2f);paint.setTextSize(40f);paint.setAntiAlias(true); //設(shè)置抗鋸齒paint.setDither(true); //設(shè)置防抖動(dòng)Path path = new Path();//以(600,600)為圓心,300為半徑繪制圓//Path.Direction.CW順時(shí)針繪制圓 Path.Direction.CCW逆時(shí)針繪制圓path.addCircle(600, 600, 300, Path.Direction.CCW);//沿path繪制文字canvas.drawTextOnPath("我是Layne,在測試Direction,這是CCW逆時(shí)針繪制圓", path, 0, 0, paint);canvas.drawPath(path, paint);

結(jié)果對比:

其他圖形繪制示例:

Paint paint = new Paint();paint.setStyle(Paint.Style.STROKE); //只描邊paint.setColor(Color.BLUE);paint.setStrokeWidth(10f);paint.setAntiAlias(true); //設(shè)置抗鋸齒paint.setDither(true); //設(shè)置防抖動(dòng)Path path = new Path();//以(400,200)為圓心,半徑為100繪制圓path.addCircle(550, 200, 100, Path.Direction.CW);//繪制橢圓RectF rectF = new RectF(100, 350, 500, 600);//第一種方法繪制橢圓path.addOval(rectF, Path.Direction.CW);//第二種方法繪制橢圓path.addOval(600, 350, 1000, 600, Path.Direction.CW);//繪制矩形RectF rect = new RectF(100, 650, 500, 900);//第一種方法繪制矩形path.addRect(rect, Path.Direction.CW);//第一種方法繪制矩形path.addRect(600, 650, 1000, 900, Path.Direction.CCW);//繪制圓角矩形RectF roundRect = new RectF(100, 950, 300, 1100);//第一種方法繪制圓角矩形path.addRoundRect(roundRect, 20, 20, Path.Direction.CW);//第二種方法繪制圓角矩形path.addRoundRect(350, 950, 550, 1100, 10, 50, Path.Direction.CCW);//第三種方法繪制圓角矩形//float[] radii中有8個(gè)值,依次為左上角,右上角,右下角,左下角的rx,ryRectF roundRectT = new RectF(600, 950, 800, 1100);path.addRoundRect(roundRectT, new float[]{50, 50, 50, 50, 50, 50, 0, 0}, Path.Direction.CCW);//第四種方法繪制圓角矩形path.addRoundRect(850, 950, 1050, 1100,new float[]{0, 0, 0, 0,50, 50, 50, 50}, Path.Direction.CCW);canvas.drawPath(path, paint);

結(jié)果:



### 繪制圓弧 //繪制圓弧 addArc(RectF oval, float startAngle, float sweepAngle) addArc(float left, float top, float right, float bottom, float startAngle,float sweepAngle)//forceMoveTo:是否強(qiáng)制將path最后一個(gè)點(diǎn)移動(dòng)到圓弧起點(diǎn), //true是強(qiáng)制移動(dòng),即為不連接兩個(gè)點(diǎn);false則連接兩個(gè)點(diǎn) arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo) arcTo(RectF oval, float startAngle, float sweepAngle) arcTo(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean forceMoveTo)

addArc()和arcTo()都是添加圓弧到path中,不過他們之間還是有區(qū)別的。addArc()是直接添加圓弧到path中;而arcTo()會(huì)判斷要繪制圓弧的起點(diǎn)與繪制圓弧之前path中最后的點(diǎn)是否是同一個(gè)點(diǎn),如果不是同一個(gè)點(diǎn)的話,就會(huì)連接兩個(gè)點(diǎn)。

演示一下:

Paint paint = new Paint();paint.setStyle(Paint.Style.STROKE); //只描邊paint.setColor(Color.BLUE);paint.setStrokeWidth(20f);paint.setAntiAlias(true); //設(shè)置抗鋸齒paint.setDither(true); //設(shè)置防抖動(dòng)Path path = new Path();//在F(400, 200, 700, 500)區(qū)域內(nèi)繪制一個(gè)270度的圓弧RectF rectF = new RectF(400, 200, 700, 500);path.addArc(rectF, 0, 270);//在(400, 600, 600, 800)區(qū)域內(nèi)繪制一個(gè)90度的圓弧,并且不連接兩個(gè)點(diǎn)RectF rectFTo = new RectF(400, 600, 700, 900);path.arcTo(rectFTo, 0, 180, true); //等價(jià)于path.addArc(rectFTo, 0, 180);canvas.drawPath(path, paint);

結(jié)果:

把上面代碼修改成連接兩點(diǎn):

path.arcTo(rectFTo, 0, 180, false); //等價(jià)于path.addArc(rectFTo, 0, 180);

結(jié)果:



閉合path操作

如果path的重點(diǎn)和起始點(diǎn)不是同一個(gè)點(diǎn)的話,那么path.close()就會(huì)連接這兩個(gè)點(diǎn),形成一個(gè)封閉的圖形。演示一下:

Paint paint = new Paint();paint.setStyle(Paint.Style.STROKE); //只描邊paint.setColor(Color.BLUE);paint.setStrokeWidth(20f);paint.setAntiAlias(true); //設(shè)置抗鋸齒paint.setDither(true); //設(shè)置防抖動(dòng)Path path = new Path();//在F(400, 200, 700, 500)區(qū)域內(nèi)繪制一個(gè)270度的圓弧RectF rectF = new RectF(400, 200, 700, 500);path.addArc(rectF, 0, 270);// path.close(); //先注釋canvas.drawPath(path, paint);

結(jié)果:

接下來解掉path.close()的注釋,再運(yùn)行一次,結(jié)果:



貝塞爾曲線

貝塞爾曲線就麻煩多了,也復(fù)雜多了。這里不詳細(xì)說明了,再網(wǎng)上找到一篇說明比較詳細(xì)的文章。
安卓自定義View進(jìn)階 - 貝塞爾曲線

這里直接復(fù)制了里面的二階曲線的實(shí)現(xiàn):

public class CanvasView extends View {private Paint mPaint;private int centerX, centerY;private PointF start, end, control;public CanvasView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);mPaint = new Paint();mPaint.setColor(Color.BLACK);mPaint.setStrokeWidth(8);mPaint.setStyle(Paint.Style.STROKE);mPaint.setTextSize(60);start = new PointF(0, 0);end = new PointF(0, 0);control = new PointF(0, 0);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);centerX = w / 2;centerY = h / 2;// 初始化數(shù)據(jù)點(diǎn)和控制點(diǎn)的位置start.x = centerX - 200;start.y = centerY;end.x = centerX + 200;end.y = centerY;control.x = centerX;control.y = centerY - 100;}@Overridepublic boolean onTouchEvent(MotionEvent event) {// 根據(jù)觸摸位置更新控制點(diǎn),并提示重繪control.x = event.getX();control.y = event.getY();invalidate();//刷新View,重新繪制return true;}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);// 繪制數(shù)據(jù)點(diǎn)和控制點(diǎn)mPaint.setColor(Color.GRAY);mPaint.setStrokeWidth(20);canvas.drawPoint(start.x, start.y, mPaint);canvas.drawPoint(end.x, end.y, mPaint);canvas.drawPoint(control.x, control.y, mPaint);// 繪制輔助線mPaint.setStrokeWidth(4);canvas.drawLine(start.x, start.y, control.x, control.y, mPaint);canvas.drawLine(end.x, end.y, control.x, control.y, mPaint);// 繪制貝塞爾曲線mPaint.setColor(Color.RED);mPaint.setStrokeWidth(8);Path path = new Path();path.moveTo(start.x, start.y);path.quadTo(control.x, control.y, end.x, end.y);canvas.drawPath(path, mPaint);} }

結(jié)果:

關(guān)注個(gè)人公眾號「技術(shù)人的日常」,關(guān)注后回復(fù):安卓基礎(chǔ),即可獲取Android基礎(chǔ)入門學(xué)習(xí)資料。


參考資料:[https://www.jianshu.com/p/9ad3aaae0c63](https://www.jianshu.com/p/9ad3aaae0c63)

總結(jié)

以上是生活随笔為你收集整理的自定义View中Canvas之Path的详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。