目錄介紹
- 1.Paint畫筆介紹
- 1.1 圖形繪制
- 1.2 文本繪制
- 2.Canvas畫布介紹
- 2.1 設(shè)置屬性
- 2.2 畫圖【重點(diǎn)】
- 2.3 Canvas對(duì)象的獲取方式
- 2.4 Canvas的作用
- 2.5 Canvas繪制圓和橢圓
- 2.6 Canvas繪制矩形、圓角矩形
- 2.7 Canvas繪制文字
- 2.8 Canvas繪制弧形、封閉弧形
- 2.9 Canvas繪制Path路徑
- 3.Matrix變換矩陣介紹
- 3.1 translate平移
- 3.2 rorate旋轉(zhuǎn)
- 3.3 scale縮放
- 3.4 skew扭曲
- 4.RectF介紹
- 4.1 Rect簡(jiǎn)單屬性
- 4.2 Rect父類的實(shí)現(xiàn)
- 4.3 Rect常用的一些方法
- 5.關(guān)于使用到這幾個(gè)屬性的自定義View
- 5.0 知道了這幾個(gè),需要練手寫下案例
- 5.1 自定義輪播圖圓點(diǎn)
- 5.2 自定義圓環(huán)百分比進(jìn)度條
好消息
- 所有的學(xué)習(xí)筆記,開源項(xiàng)目,還有博客均已經(jīng)在GitHub開源,大多數(shù)都是markdown格式的。鏈接地址:https://github.com/yangchong211/YCBlogs
- 關(guān)于案例已經(jīng)開源,開源地址:https://github.com/yangchong211
1.Paint畫筆介紹
- Paint即畫筆,在繪圖過程中起到了極其重要的作用,畫筆主要保存了顏色, 樣式等繪制信息,指定了如何繪制文本和圖形,畫筆對(duì)象有很多設(shè)置方法,大體上可以分為兩類,一類與圖形繪制相關(guān),一類與文本繪制相關(guān)。
1.1 圖形繪制
- 常用的方法有這些
* setARGB(int a,int r,int g,int b); 設(shè)置繪制的顏色,a代表透明度,r,g,b代表顏色值。 * setAlpha(int a); 設(shè)置繪制圖形的透明度。 * setColor(int color); 設(shè)置繪制的顏色,使用顏色值來(lái)表示,該顏色值包括透明度和RGB顏色。 * setAntiAlias(boolean aa); 設(shè)置是否使用抗鋸齒功能,會(huì)消耗較大資源,繪制圖形速度會(huì)變慢。 * setDither(boolean dither); 設(shè)定是否使用圖像抖動(dòng)處理,會(huì)使繪制出來(lái)的圖片顏色更加平滑和飽滿,圖像更加清晰 * setFilterBitmap(boolean filter); 如果該項(xiàng)設(shè)置為true,則圖像在動(dòng)畫進(jìn)行中會(huì)濾掉對(duì)Bitmap圖像的優(yōu)化操作,加快顯示速度,本設(shè)置項(xiàng)依賴于dither和xfermode的設(shè)置 * setMaskFilter(MaskFilter maskfilter); 設(shè)置MaskFilter,可以用不同的MaskFilter實(shí)現(xiàn)濾鏡的效果,如濾化,立體等 * setColorFilter(ColorFilter colorfilter); 設(shè)置顏色過濾器,可以在繪制顏色時(shí)實(shí)現(xiàn)不用顏色的變換效果 * setPathEffect(PathEffect effect); 設(shè)置繪制路徑的效果,如點(diǎn)畫線等 * setShader(Shader shader); 設(shè)置圖像效果,使用Shader可以繪制出各種漸變效果 * setShadowLayer(float radius ,float dx,float dy,int color); 在圖形下面設(shè)置陰影層,產(chǎn)生陰影效果,radius為陰影的角度,dx和dy為陰影在x軸和y軸上的距離,color為陰影的顏色 * setStyle(Paint.Style style); 設(shè)置畫筆的樣式,為FILL,F(xiàn)ILL_AND_STROKE,或STROKE * setStrokeCap(Paint.Cap cap); 當(dāng)畫筆樣式為STROKE或FILL_AND_STROKE時(shí),設(shè)置筆刷的圖形樣式,如圓形樣式 Cap.ROUND,或方形樣式Cap.SQUARE * setSrokeJoin(Paint.Join join); 設(shè)置繪制時(shí)各圖形的結(jié)合方式,如平滑效果等 * setStrokeWidth(float width); 當(dāng)畫筆樣式為STROKE或FILL_AND_STROKE時(shí),設(shè)置筆刷的粗細(xì)度 * setXfermode(Xfermode xfermode); 設(shè)置圖形重疊時(shí)的處理方式,如合并,取交集或并集,經(jīng)常用來(lái)制作橡皮的擦除效果
1.2 文本繪制
- 常用的方法有這些
* setFakeBoldText(boolean fakeBoldText); 模擬實(shí)現(xiàn)粗體文字,設(shè)置在小字體上效果會(huì)非常差 * setSubpixelText(boolean subpixelText); 設(shè)置該項(xiàng)為true,將有助于文本在LCD屏幕上的顯示效果 * setTextAlign(Paint.Align align); 設(shè)置繪制文字的對(duì)齊方向 * setTextScaleX(float scaleX); 設(shè)置繪制文字x軸的縮放比例,可以實(shí)現(xiàn)文字的拉伸的效果 * setTextSize(float textSize); 設(shè)置繪制文字的字號(hào)大小 * setTextSkewX(float skewX); 設(shè)置斜體文字,skewX為傾斜弧度 * setTypeface(Typeface typeface); 設(shè)置Typeface對(duì)象,即字體風(fēng)格,包括粗體,斜體以及襯線體,非襯線體等 * setUnderlineText(boolean underlineText); 設(shè)置帶有下劃線的文字效果 * setStrikeThruText(boolean strikeThruText); 設(shè)置帶有刪除線的效果
2.Canvas畫布介紹
- 當(dāng)我們調(diào)整好畫筆之后,現(xiàn)在需要繪制到畫布上,這就得用Canvas類了。在android中既然把Canvas當(dāng)做畫布,那么就可以在畫布上繪制我們想要的任何東西。除了在畫布上繪制之外,還需要設(shè)置一些關(guān)于畫布的屬性,比如,畫布的顏色、尺寸等。
2.1 設(shè)置屬性
- 一般屬性有:
* Canvas(Bitmap bitmap): 以bitmap對(duì)象創(chuàng)建一個(gè)畫布,則將內(nèi)容都繪制在bitmap上,因此bitmap不得為null。 * Canvas(GL gl): 在繪制3D效果時(shí)使用,與OpenGL相關(guān)。 * isOpaque(boolean isOpaque):檢測(cè)是否支持透明。 * setViewport(int left, int top, int right, int bottom, int clipflag): 設(shè)置畫布中顯示窗口。 * drawColor(int color): 設(shè)置Canvas的背景顏色。 * setBitmap(Bitmap mBitmap): 設(shè)置具體畫布,畫的內(nèi)容,保存為一個(gè)Bitmap。 * clipRect(float left, float top, float right, float bottom): 設(shè)置顯示區(qū)域,即設(shè)置裁剪區(qū)。 * translate(float x, float y): 平移畫布。 * rotate(float degree, float px, float py): 旋轉(zhuǎn)畫布 。 * skew(float sx, float sy): 設(shè)置偏移量。 * save(): 將Canvas當(dāng)前狀態(tài)保存在堆棧,save之后可以調(diào)用Canvas的平移、旋轉(zhuǎn)、錯(cuò)切、剪裁等操作。 * restore(): 恢復(fù)為之前堆棧保存的Canvas狀態(tài),防止save后對(duì)Canvas執(zhí)行的操作對(duì)后續(xù)的繪制有影響。restore和save要配對(duì)使用,restore可以比save少,但不能比save多,否則會(huì)引發(fā)error。save和restore之間,往往夾雜的是對(duì)Canvas的特殊操作。 * save(int num):將Canvas當(dāng)前狀態(tài)保存在堆棧,并予以編號(hào)int * restoreToCount(int num):恢復(fù)為之前堆棧保存的編號(hào)為int的Canvas狀態(tài) * concat(Matrix matrix):畫布關(guān)聯(lián)矩陣,畫出來(lái)的內(nèi)容按矩陣改變,而不是畫布改變。 * Drawable.draw(Canvas canvas):將Drawable畫到Canvas中 注:這種方式畫Drawable怎么設(shè)置透明度呢?((BitmapDrawable)Drawable).getPaint().setAlpha(mBgAlpha);
2.2 畫圖【重點(diǎn)】
- 畫圖部分
* canvas.drawPaint(Paint paint) 將畫筆設(shè)置的顏色和透明度鋪滿畫布 * drawRect(RectF rect, Paint paint) 繪制矩形,參數(shù)一為RectF一個(gè)區(qū)域 * drawRect(float left, float top, float right, float bottom, Paint paint) 繪制矩形,left:矩形left的x坐標(biāo),top:矩形top的y坐標(biāo),right:矩形right的x坐標(biāo),bottom:矩形bottom的y坐標(biāo) * drawRoundRect(RectF rect, float rx, float ry, Paint paint) 繪制圓角矩形, rx:x方向的圓角半徑,ry:y方向的圓角半徑 * drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, Paint paint) * drawPath(Path path, Paint paint) 繪制一個(gè)路徑,參數(shù)一為Path路徑對(duì)象 * drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) 貼圖,參數(shù)一就是我們常規(guī)的Bitmap對(duì)象,參數(shù)二是源區(qū)域(這里是bitmap),參數(shù)三是目標(biāo)區(qū)域(應(yīng)該在canvas的位置和大小),參數(shù)四是Paint畫刷對(duì)象,因?yàn)橛玫搅丝s放和拉伸的可能,當(dāng)原始Rect不等于目標(biāo)Rect時(shí)性能將會(huì)有大幅損失。 * drawBitmap (Bitmap bitmap, float left, float top, Paint paint) * drawLine(float startX, float startY, float stopX, float stopY, Paintpaint) 畫線,參數(shù)一起始點(diǎn)的x軸位置,參數(shù)二起始點(diǎn)的y軸位置,參數(shù)三終點(diǎn)的x軸水平位置,參數(shù)四y軸垂直位置,最后一個(gè)參數(shù)為Paint 畫刷對(duì)象。 * drawPoint(float x, float y, Paint paint) 畫點(diǎn),參數(shù)一水平x軸,參數(shù)二垂直y軸,第三個(gè)參數(shù)為Paint對(duì)象。 * drawText(String text, float x, floaty, Paint paint) 渲染文本,Canvas類除了上面的還可以描繪文字,參數(shù)一是String類型的文本,參數(shù)二文字左側(cè)到x軸距離,參數(shù)三文字BaseLine到y(tǒng)軸距離,參數(shù)四是Paint對(duì)象。 * drawOval(RectF oval, Paint paint) 繪制橢圓,參數(shù)一是掃描區(qū)域,參數(shù)二為paint對(duì)象 * drawOval(float left, float top, float right, float bottom, Paint paint) * drawCircle(float cx, float cy, float radius,Paint paint) 繪制圓,參數(shù)一是中心點(diǎn)的x軸,參數(shù)二是中心點(diǎn)的y軸,參數(shù)三是半徑,參數(shù)四是paint對(duì)象; * drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint) 畫弧,參數(shù)一是RectF對(duì)象,指定圓弧的外輪廓矩形區(qū)域,參數(shù)二是起始角(度)在電弧的開始,參數(shù)三掃描角(度)開始順時(shí)針測(cè)量的,參數(shù)四是如果這是真的話,包括橢圓中心的電弧,并關(guān)閉它,如果它是假這將是一個(gè)弧線,參數(shù)五是Paint對(duì)象;
2.3 Canvas對(duì)象的獲取方式
- 2.3.1 Canvas對(duì)象的獲取方式有兩種:
- 第一種通過重寫View.onDraw方法,View中的Canvas對(duì)象會(huì)被當(dāng)做參數(shù)傳遞過來(lái),操作這個(gè)Canvas,效果會(huì)直接反應(yīng)在View中。
- 第二種通過new創(chuàng)建一個(gè)Canvas對(duì)象
- 代碼如下所示
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); } Canvas canvas = new Canvas();
2.4 Canvas的作用
- Canvas可以繪制的對(duì)象有:弧線(arcs)、填充顏色(argb和color)、Bitmap、圓(circle和oval)、點(diǎn)(point)、線(line)、矩形(Rect)、圖片(Picture)、圓角矩形(RoundRect)、文本(text)、頂點(diǎn)(Vertices)、路徑(path)。
2.5 Canvas繪制圓和橢圓
- 繪制圓
private Paint paint = new Paint(); @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); paint.setAntiAlias(true); paint.setColor(Color.BLUE); paint.setStyle(Paint.Style.FILL); canvas.drawCircle(200,200,100 , paint); }
2.6 Canvas繪制矩形、圓角矩形
- 如下所示
-
image
private Paint paint = new Paint(); @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); paint.setAntiAlias(true); paint.setColor(Color.RED); paint.setStyle(Paint.Style.FILL); canvas.drawRect(100, 100, 200, 200, paint); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { canvas.drawRoundRect(400, 100, 600, 300, 30, 30, paint); } paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(20); canvas.drawRect(100, 400, 300, 600, paint); }
2.7 Canvas繪制文字
- Canvas繪制文字
-
image
private Paint paint = new Paint(); @SuppressLint("DrawAllocation") @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); paint.setAntiAlias(true); paint.setColor(Color.RED); paint.setTextSize(100); canvas.drawText("瀟湘劍雨", 100, 100, paint); }
2.8 Canvas繪制弧形、封閉弧形
- 繪制弧形、封閉弧形
-
image
private Paint paint = new Paint(); @SuppressLint("DrawAllocation") @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); paint.setAntiAlias(true); paint.setColor(Color.RED); RectF rel = new RectF(50, 50, 150, 150); //實(shí)心圓弧 canvas.drawArc(rel, 0, 135, false, paint); //實(shí)心圓弧 將圓心包含在內(nèi) RectF rel2 = new RectF(50, 200, 150, 300); canvas.drawArc(rel2, 0, 135, true, paint); //設(shè)置空心Style paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(20); RectF rel3 = new RectF(50, 350, 150, 450); canvas.drawArc(rel3, 0, 270, false, paint); RectF rel4 = new RectF(50, 250, 150, 600); canvas.drawArc(rel4, 0, 270, true, paint); }
2.9 Canvas繪制Path路徑
- Canvas繪制Path路徑
-
image
private Paint paint = new Paint(); @SuppressLint("DrawAllocation") @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Path angle = new Path(); angle.moveTo(250, 0); angle.lineTo(0, 500); angle.lineTo(100, 300); angle.lineTo(200, 350); angle.lineTo(500, 500); angle.close(); canvas.drawPath(angle, paint); }
3.Matrix變換矩陣介紹【Canvas位置轉(zhuǎn)換】
- 思考:如果要畫一個(gè)儀表盤(數(shù)字圍繞顯示在一個(gè)圓圈中),或者類似鐘表指針樣的控件,如何實(shí)現(xiàn)?
- Android還提供了一些對(duì)Canvas位置轉(zhuǎn)換的方法:rorate、scale、translate、skew(扭曲)等,而且它允許你通過獲得它的轉(zhuǎn)換矩陣對(duì)象(getMatrix方法)直接操作它。這些操作就像是雖然你的筆還是原來(lái)的地方畫,但是畫紙旋轉(zhuǎn)或者移動(dòng)了,所以你畫的東西的方位就產(chǎn)生變化。為了方便一些轉(zhuǎn)換操作,Canvas還提供了保存和回滾屬性的方法(save和restore),比如你可以先保存目前畫紙的位置(save),然后旋轉(zhuǎn)90度,向下移動(dòng)100像素后畫一些圖形,畫完后調(diào)用restore方法返回到剛才保存的位置。
3.1 translate平移
3.2 rorate旋轉(zhuǎn)
- rorate旋轉(zhuǎn)
-
image
private Paint mPaint = new Paint(); @SuppressLint("DrawAllocation") @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.BLUE); mPaint.setColor(Color.RED); canvas.drawRect(new Rect(0, 0, 800, 800), mPaint); canvas.save(); mPaint.setColor(Color.GREEN); canvas.rotate(45,400,400); canvas.drawRect(new Rect(0, 0, 800, 800), mPaint); canvas.restore(); } - 源代碼有兩個(gè)可以使用的方法:
/** * Preconcat the current matrix with the specified rotation. * @param degrees The amount to rotate, in degrees */ public native void rotate(float degrees); /** * Preconcat the current matrix with the specified rotation. * @param degrees The amount to rotate, in degrees * @param px The x-coord for the pivot point (unchanged by the rotation) * @param py The y-coord for the pivot point (unchanged by the rotation) */ public final void rotate(float degrees, float px, float py) { translate(px, py); rotate(degrees); translate(-px, -py); }
3.3 scale縮放
- scale縮放
-
image
private Paint mPaint = new Paint(); @SuppressLint("DrawAllocation") @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.YELLOW); mPaint.setColor(Color.RED); canvas.drawRect(new Rect(0, 0, 800, 800), mPaint); // 保存畫布狀態(tài) canvas.save(); canvas.scale(0.5f, 0.5f); mPaint.setColor(Color.GREEN); canvas.drawRect(new Rect(0, 0, 800, 800), mPaint); // 畫布狀態(tài)回滾 canvas.restore(); canvas.scale(0.5f, 0.5f, 400, 400); mPaint.setColor(Color.BLUE); canvas.drawRect(new Rect(0, 0, 800, 800), mPaint); } - 源碼如下所示
/** * Preconcat the current matrix with the specified scale. * @param sx The amount to scale in X * @param sy The amount to scale in Y */ public native void scale(float sx, float sy); /** * Preconcat the current matrix with the specified scale. * @param sx The amount to scale in X * @param sy The amount to scale in Y * @param px The x-coord for the pivot point (unchanged by the scale) * @param py The y-coord for the pivot point (unchanged by the scale) */ public final void scale(float sx, float sy, float px, float py) { translate(px, py); scale(sx, sy); translate(-px, -py); }
3.4 skew扭曲
4.RectF介紹
4.1 Rect簡(jiǎn)單屬性
- 這是一個(gè)我們常用的一個(gè)“繪畫相關(guān)的工具類”,常用語(yǔ)描述長(zhǎng)方形/正方形,他只有4個(gè)屬性
public int left; public int top; public int right; public int bottom; - 其中常用的構(gòu)造方法如下所示
public Rect(int left, int top, int right, int bottom) { this.left = left; this.top = top; this.right = right; this.bottom = bottom; } public Rect(Rect r) { if (r == null) { left = top = right = bottom = 0; } else { left = r.left; top = r.top; right = r.right; bottom = r.bottom; } } - 這4個(gè)屬性描述著這一個(gè)“方塊”,但是這有一個(gè)知識(shí)點(diǎn)需要理清楚,先看這張圖
- image
4.2 Rect父類的實(shí)現(xiàn)
- 實(shí)現(xiàn)了Parcelable 所以需要實(shí)現(xiàn)一堆Object的方法,諸如equals,toString等等,來(lái)簡(jiǎn)單看一看
- 對(duì)于equals方法,首先先對(duì)傳來(lái)的對(duì)象進(jìn)行判空,類型判斷,再?gòu)?qiáng)轉(zhuǎn)成Rect對(duì)象,最后還是一個(gè)個(gè)去比對(duì)那4個(gè)屬性。
@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Rect r = (Rect) o; return left == r.left && top == r.top && right == r.right && bottom == r.bottom; } @Override public int hashCode() { int result = left; result = 31 * result + top; result = 31 * result + right; result = 31 * result + bottom; return result; } @Override public String toString() { StringBuilder sb = new StringBuilder(32); sb.append("Rect("); sb.append(left); sb.append(", "); sb.append(top); sb.append(" - "); sb.append(right); sb.append(", "); sb.append(bottom); sb.append(")"); return sb.toString(); }
4.3 Rect常用的一些方法
- 獲取“寬”
//文章開頭說(shuō)的公式在這里得到了應(yīng)驗(yàn) public final int width() { return right - left; } - 獲取“高”
public final int height() { return bottom - top; } - 有效性的判斷
//因?yàn)閘eft是最左側(cè),right比left還小不就不成形了么?寬高同是如此 public final boolean isEmpty() { return left >= right || top >= bottom; } - 全部置0操作
public void setEmpty() { left = right = top = bottom = 0; } - 設(shè)置參數(shù)方法,和構(gòu)造函數(shù)的區(qū)別僅在于不會(huì)創(chuàng)建新對(duì)象
public void set(int left, int top, int right, int bottom) { this.left = left; this.top = top; this.right = right; this.bottom = bottom; }
5.關(guān)于使用到這幾個(gè)屬性的自定義View
- 上面比較詳細(xì)介紹了Canvas,Paint,Matrix,RectF等等的屬性,作用,常用方法,接下來(lái)就需要結(jié)合具體業(yè)務(wù)需求練手寫一下小案例自定義控件呢
5.1 自定義輪播圖圓點(diǎn)
- 5.1.1 需求介紹
- 繪制圓環(huán),一個(gè)實(shí)心中心圓,還有一個(gè)外圓環(huán)
- 此控件可以設(shè)置寬度和高度,可以設(shè)置顏色
- 5.1.2 思路介紹
- 3.2.1 既然是繪制圓形,可以寫一個(gè)繼承View的自定義view
- 3.2.2 重寫onDraw方法,獲取控件寬高,然后比較寬高值,取小值的一半作為圓的半徑
- 3.2.3 然后分別繪制選中狀態(tài)和未選中狀態(tài)的圓
- 3.2.4 創(chuàng)建畫筆Paint,并且設(shè)置相關(guān)屬性,比如畫筆顏色,類型等
- 3.2.5 利用canvas繪制圓,然后再又用相同方法繪制外邊緣
- 3.2.6 自定義一個(gè)是否選中狀態(tài)的方法,傳入布爾值是否選中,然后調(diào)用view中invalidate方法
- 5.1.3 代碼介紹
- 具體代碼如下所示:
/** * <pre> * @author yangchong * blog : https://github.com/yangchong211 * time : 2016/5/18 * desc : 紅點(diǎn)自定義控件 * revise: 建議設(shè)置紅點(diǎn)寬高一樣,否則是橢圓 * </pre> */ public class DotView extends View { private boolean isInit = false; private boolean isSelected = false; private float mViewHeight; private float mViewWidth; private float mRadius; private Paint mPaintBg = new Paint(); private int mBgUnselectedColor = Color.parseColor("#1A000000"); private int mBgSelectedColor = Color.parseColor("#FDE26E"); private static final float mArcWidth = 2.0f; public DotView(Context context) { super(context); } public DotView(Context context, AttributeSet attrs) { super(context, attrs); } public DotView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (!isInit) { isInit = true; mViewHeight = getHeight(); mViewWidth = getWidth(); if (mViewHeight >= mViewWidth) { mRadius = mViewWidth / 2.f; } else { mRadius = mViewHeight / 2.f; } } //是否選中 if (isSelected){ drawSelectedDot(canvas); } else{ drawUnSelectedDot(canvas); } } /** * 繪制選中指示器紅點(diǎn) * @param canvas canvas */ private void drawSelectedDot(Canvas canvas) { //設(shè)置paint相關(guān)屬性 mPaintBg.setAntiAlias(true); mPaintBg.setColor(mBgSelectedColor); mPaintBg.setStyle(Style.FILL); //繪制圓 canvas.drawCircle(mViewWidth / 2.f, mViewHeight / 2.f, mRadius - 8.f, mPaintBg); mPaintBg.setStyle(Style.STROKE); float offset = 1.f + mArcWidth; RectF oval = new RectF(mViewWidth / 2.f - mRadius + offset, mViewHeight / 2.f - mRadius + offset, mViewWidth / 2.f + mRadius - offset, mViewHeight / 2.f + mRadius - offset); //繪制指定的弧線,該弧線將被縮放以適應(yīng)指定的橢圓形。 canvas.drawArc(oval, 0.f, 360.f, false, mPaintBg); } /** * 繪制未選中指示器紅點(diǎn) * @param canvas canvas */ private void drawUnSelectedDot(Canvas canvas) { mPaintBg.setAntiAlias(true); mPaintBg.setColor(mBgUnselectedColor); mPaintBg.setStyle(Style.FILL); canvas.drawCircle(mViewWidth / 2.f, mViewHeight / 2.f, mRadius - 8.f, mPaintBg); } /** * 設(shè)置是否選中 * @param isSelected isSelected */ public void setIsSelected(boolean isSelected) { this.isSelected = isSelected; //使整個(gè)視圖無(wú)效。如果視圖是可見的,則{@link#onDraw(android.Graphics.Canvas)}將在將來(lái)的某個(gè)時(shí)候被調(diào)用。 //調(diào)用該方法,會(huì)進(jìn)行重新繪制,也就是調(diào)用onDraw方法 this.invalidate(); } }
5.2 自定義圓環(huán)百分比進(jìn)度條
- 5.2.1 需求分析
- 1.業(yè)務(wù)需求:可以設(shè)置圓角,可以設(shè)置圓形,如果是圓角則必須設(shè)置半徑,默認(rèn)圓角半徑為10dp
- 2.如果設(shè)置了圓形,則即使設(shè)置圓角也無(wú)效;如果設(shè)置非圓形,則圓角生效,同時(shí)需要判斷圓角半徑是否大于控件寬高,處理邊界邏輯
- 3.當(dāng)設(shè)置圓形的時(shí)候,即使設(shè)置寬高不一樣,那么取寬高中的最小值的一半為圓形半徑
- 5.2.2 代碼介紹
- 代碼如下所示
public class ARoundImageView extends AppCompatImageView { /* * Paint:畫筆 * Canvas:畫布 * Matrix:變換矩陣 * * 業(yè)務(wù)需求:可以設(shè)置圓角,可以設(shè)置圓形,如果是圓角則必須設(shè)置半徑,默認(rèn)圓角半徑為10dp */ /** * 圓形模式 */ private static final int MODE_CIRCLE = 1; /** * 普通模式 */ private static final int MODE_NONE = 0; /** * 圓角模式 */ private static final int MODE_ROUND = 2; /** * 圓角半徑 */ private int currRound = dp2px(10); /** * 畫筆 */ private Paint mPaint; /** * 默認(rèn)是普通模式 */ private int currMode = 0; public ARoundImageView(Context context) { this(context,null); } public ARoundImageView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ARoundImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); obtainStyledAttrs(context, attrs, defStyleAttr); initViews(); } private void obtainStyledAttrs(Context context, AttributeSet attrs, int defStyleAttr) { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ARoundImageView, defStyleAttr, 0); currMode = a.hasValue(R.styleable.ARoundImageView_type) ? a.getInt(R.styleable.ARoundImageView_type, MODE_NONE) : MODE_NONE; currRound = a.hasValue(R.styleable.ARoundImageView_radius) ? a.getDimensionPixelSize(R.styleable.ARoundImageView_radius, currRound) : currRound; a.recycle(); } private void initViews() { //ANTI_ALIAS_FLAG 用于繪制時(shí)抗鋸齒 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); } /** * 當(dāng)模式為圓形模式的時(shí)候,我們強(qiáng)制讓寬高一致 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (currMode == MODE_CIRCLE) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int result = Math.min(getMeasuredHeight(), getMeasuredWidth()); // 此方法必須由{@link#onMeasure(int,int)}調(diào)用,以存儲(chǔ)已測(cè)量的寬度和測(cè)量的高度。 // 如果不這樣做,將在測(cè)量時(shí)觸發(fā)異常。 setMeasuredDimension(result, result); } else { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } } @SuppressLint("DrawAllocation") @Override protected void onDraw(Canvas canvas) { //獲取ImageView圖片資源 Drawable mDrawable = getDrawable(); //獲取Matrix對(duì)象 Matrix mDrawMatrix = getImageMatrix(); if (mDrawable == null) { return; } if (mDrawable.getIntrinsicWidth() == 0 || mDrawable.getIntrinsicHeight() == 0) { return; } if (mDrawMatrix == null && getPaddingTop() == 0 && getPaddingLeft() == 0) { mDrawable.draw(canvas); } else { final int saveCount = canvas.getSaveCount(); canvas.save(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { if (getCropToPadding()) { final int scrollX = getScrollX(); final int scrollY = getScrollY(); canvas.clipRect(scrollX + getPaddingLeft(), scrollY + getPaddingTop(), scrollX + getRight() - getLeft() - getPaddingRight(), scrollY + getBottom() - getTop() - getPaddingBottom()); } } canvas.translate(getPaddingLeft(), getPaddingTop()); switch (currMode){ case MODE_CIRCLE: Bitmap bitmap1 = drawable2Bitmap(mDrawable); mPaint.setShader(new BitmapShader(bitmap1, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); canvas.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2, mPaint); break; case MODE_ROUND: Bitmap bitmap2 = drawable2Bitmap(mDrawable); mPaint.setShader(new BitmapShader(bitmap2, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); canvas.drawRoundRect(new RectF(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()), currRound, currRound, mPaint); break; case MODE_NONE: default: if (mDrawMatrix != null) { canvas.concat(mDrawMatrix); } mDrawable.draw(canvas); break; } canvas.restoreToCount(saveCount); } } /** * drawable轉(zhuǎn)換成bitmap */ private Bitmap drawable2Bitmap(Drawable drawable) { if (drawable == null) { return null; } Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); //根據(jù)傳遞的scaleType獲取matrix對(duì)象,設(shè)置給bitmap Matrix matrix = getImageMatrix(); if (matrix != null) { canvas.concat(matrix); } drawable.draw(canvas); return bitmap; } private int dp2px(float value) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, getResources().getDisplayMetrics()); } }
關(guān)于其他內(nèi)容介紹
01.關(guān)于博客匯總鏈接
- 1.技術(shù)博客匯總
- 2.開源項(xiàng)目匯總
- 3.生活博客匯總
- 4.喜馬拉雅音頻匯總
- 5.其他匯總
02.關(guān)于我的博客
- 我的個(gè)人站點(diǎn):www.yczbj.org,www.ycbjie.cn
- github:https://github.com/yangchong211
- 知乎:https://www.zhihu.com/people/yang-chong-69-24/pins/posts
- 簡(jiǎn)書:http://www.itdecent.cn/u/b7b2c6ed9284
- csdn:http://my.csdn.net/m0_37700275
- 喜馬拉雅聽書:http://www.ximalaya.com/zhubo/71989305/
- 開源中國(guó):https://my.oschina.net/zbj1618/blog
- 泡在網(wǎng)上的日子:http://www.jcodecraeer.com/member/content_list.php?channelid=1
- 郵箱:yangchong211@163.com
- 阿里云博客:https://yq.aliyun.com/users/article?spm=5176.100- 239.headeruserinfo.3.dT4bcV
- segmentfault頭條:https://segmentfault.com/u/xiangjianyu/articles






