onMeasure
這意味著我們的自定義View到了處理自己的大小的時(shí)候毡们。這是非常重要的方法衙熔,因?yàn)樵诖蠖鄶?shù)情況下搅荞,你的View需要有特定的大小以適應(yīng)你的布局红氯。
當(dāng)你重寫此方法,需要記得的是咕痛,最終要設(shè)setMeasuredDimension(int width, int height) 构蹬。
當(dāng)處理自定義View的大小時(shí)候,使用者可能通過layout.xml或者動(dòng)態(tài)設(shè)置了具體的大小兴猩。要正確地計(jì)算它,我們需要做幾件事情垛玻。
計(jì)算你的View內(nèi)容所需的大兄阕(寬度和高度)亿驾。
獲取你的View MeasureSpec大小和模式(寬度和高度)。
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
}
- 檢查MeasureSpec 設(shè)置和調(diào)整View(寬度和高度)的尺寸模式账嚎。
int width;
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize;
} else if (widthMode == MeasureSpec.AT_MOST) {
width = Math.min(desiredWidth, widthSize);
} else {
width = desiredWidth;
}
注意:
看看MeasureSpec的值:
MeasureSpec.EXACTLY 意味著硬編碼大小值莫瞬,所以你應(yīng)該設(shè)置指定的寬度或高度。
MeasureSpec.AT_MOST 用于表明你的View匹配父View的大小郭蕉,
所以它應(yīng)該和他想要的大小一樣大疼邀。
[此時(shí)View尺寸只要不超過父View允許的最大尺寸即可]MeasureSpec.UNSPECIFIED 實(shí)際上是視圖包裝尺寸。因此召锈,你可以使用上面計(jì)算所需的大小旁振。
在通過setMeasuredDimension設(shè)置最終值之前,以防萬一涨岁,可以檢查這些值不為負(fù)數(shù)拐袜。這可以避免在布局預(yù)覽時(shí)一些問題。
View 更新
從View的生命周期圖可以得知梢薪,可以重繪View自身有兩種方法蹬铺。invalidate()和requestLayout()方法會(huì)幫助你在運(yùn)行時(shí)動(dòng)態(tài)改變View狀態(tài)。但為什么需要兩個(gè)方法秉撇?
invalidate()用來簡單重繪View甜攀。例如更新其文本,色彩或觸摸交互性琐馆。View將只調(diào)用onDraw()方法再次更新其狀態(tài)规阀。
requestLayout()方法,你可以看到其將會(huì)從`onMeasure()開始更新View瘦麸。這意味著你的View更新后姥敛,它改變它的大小,你需要再次測(cè)量它瞎暑,并依賴于新的大小來重新繪制彤敛。
動(dòng)畫
在自定義View中,動(dòng)畫是一幀一幀的過程了赌。這意味著墨榄,如果你想使一個(gè)圓半徑從小變大,你將需要逐步增加半徑并調(diào)用invalidate()來重繪它勿她。
在自定義View動(dòng)畫中袄秩,ValueAnimator是你的好朋友。下面這個(gè)類將幫助你從任何值開始執(zhí)行動(dòng)畫到最后逢并,甚至支持Interpolator(如果需要)之剧。
ValueAnimator animator = ValueAnimator.ofInt(0, 100);
animator.setDuration(1000);
animator.setInterpolator(new DecelerateInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
int newRadius = (int) animation.getAnimatedValue();
}
});
注意:
當(dāng)每一次新的動(dòng)畫值出來時(shí),不要忘記調(diào)用invalidate()砍聊。
Paint類
Paint畫筆對(duì)象背稼,這個(gè)類中包含了如何繪制幾何圖形、文字和位圖的樣式和顏色信息玻蝌,指定了如何繪制文本和圖形蟹肘。畫筆對(duì)象右很多設(shè)置方法,大體上可以分為兩類:一類與圖形繪制有關(guān)俯树,一類與文本繪制有關(guān)帘腹。
Paint類中有如下方法:
1、圖形繪制:
setStyle(Paint.Style s):設(shè)置畫筆的樣式:FILL實(shí)心许饿;STROKE空心阳欲;FILL_OR_STROKE同時(shí)實(shí)心與空心;
setStrokeCap(Paint.Cap c):當(dāng)設(shè)置畫筆樣式為STROKE或FILL_OR_STROKE時(shí)陋率,設(shè)置筆刷的圖形樣式球化;
setStrokeWidth(float w):當(dāng)畫筆樣式為STROKE或FILL_OR_STROKE時(shí),設(shè)置筆刷的粗細(xì)度翘贮;
setAlpha(int a):設(shè)置繪制的圖形的透明度赊窥;
setColor(int color):設(shè)置繪制的顏色;
setAntiAlias(boolean a):設(shè)置是否使用抗鋸齒功能狸页,抗鋸齒功能會(huì)消耗較大資源锨能,繪制圖形的速度會(huì)減慢;
setArgb(int a, int r, int g, int b):設(shè)置繪制的顏色芍耘,a表示透明度址遇,r、g斋竞、b表示顏色值倔约;
setDither(boolean b):設(shè)置是否使用圖像抖動(dòng)處理,會(huì)使圖像顏色更加平滑飽滿坝初,更加清晰浸剩;
setFileterBitmap(Boolean b):設(shè)置是否在動(dòng)畫中濾掉Bitmap的優(yōu)化钾军,可以加快顯示速度;
setMaskFilter(MaskFilter mf):設(shè)置MaskFilter來實(shí)現(xiàn)濾鏡的效果绢要;
setColorFilter(ColorFilter cf):設(shè)置顏色過濾器吏恭,可以在繪制顏色時(shí)實(shí)現(xiàn)不同顏色的變換效果;
setPathEffect(PathEffect pe):設(shè)置繪制的路徑的效果重罪;
setShader(Shader s):設(shè)置Shader繪制各種漸變效果樱哼;
setShadowLayer(float r, int x, int y, int c):在圖形下面設(shè)置陰影層剿配,r為陰影角度,x和y為陰影在x軸和y軸上的距離茄唐,c為陰影的顏色砸讳;
setStrokeJoin(Paint.Join j):設(shè)置繪制時(shí)各圖形的結(jié)合方式;
setXfermode(Xfermode m):設(shè)置圖形重疊時(shí)的處理方式簿寂;
2常遂、文本繪制:
1) setTextAlign(Path.Align a):設(shè)置繪制的文本的對(duì)齊方式;
2) setTextScaleX(float s):設(shè)置文本在X軸的縮放比例平绩,可以實(shí)現(xiàn)文字的拉伸效果漠另;
3) setTextSize(float s):設(shè)置字號(hào);
4) setTextSkewX(float s):設(shè)置斜體文字性湿,s是文字傾斜度满败;
5) setTypeFace(TypeFace tf):設(shè)置字體風(fēng)格,包括粗體算墨、斜體等;
6) setUnderlineText(boolean b):設(shè)置繪制的文本是否帶有下劃線效果报咳;
7) setStrikeThruText(boolean b):設(shè)置繪制的文本是否帶有刪除線效果;
8) setFakeBoldText(boolean b):模擬實(shí)現(xiàn)粗體文字继低,如果設(shè)置在小字體上效果會(huì)非常差稍走;
9) setSubpixelText(boolean b):如果設(shè)置為true則有助于文本在LCD屏幕上顯示效果柴底;
3、其他方法:
1) getTextBounds(String t, int s, int e, Rect b):將頁面中t文本從s下標(biāo)開始到e下標(biāo)結(jié)束的所有字符所占的區(qū)域?qū)捀叻庋b到b這個(gè)矩形中狐树;
2) clearShadowLayer():清除陰影層鸿脓;
3) measureText(String t, int s, int e):返回t文本中從s下標(biāo)開始到e下標(biāo)結(jié)束的所有字符所占的寬度;
4) reset():重置畫筆為默認(rèn)值在塔。
這里需要就幾個(gè)方法解釋一下:
1拨黔、setPathEffect(PathEffect pe):設(shè)置繪制的路徑的效果:
常見的有以下幾種可選方案:
1) CornerPathEffect:可以用圓角來代替尖銳的角;
2) DathPathEffect:虛線贺待,由短線和點(diǎn)組成零截;
3) DiscretePathEffect:荊棘狀的線條;
4) PathDashPathEffect:定義一種新的形狀并將其作為原始路徑的輪廓標(biāo)記哪工;
5) SumPathEffect:在一條路徑中順序添加參數(shù)中的效果绍撞;
6) ComposePathEffect:將兩種效果組合起來傻铣,先使用第一種效果,在此基礎(chǔ)上應(yīng)用第二種效果。
2蜕径、setXfermode(Xfermode m):設(shè)置圖形重疊時(shí)的處理方式:
關(guān)于Xfermode的多種效果败京,我們可以參考下面一張圖:
在使用的時(shí)候赡麦,我們需要通過paint. setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XXX))來設(shè)置,XXX是上圖中的某種模式對(duì)應(yīng)的常量參數(shù)遂铡,如DST_OUT晶姊。
這16中情況的具體解釋如下:
1.PorterDuff.Mode.CLEAR:所繪制不會(huì)提交到畫布上。
2.PorterDuff.Mode.SRC:顯示上層繪制圖片
3.PorterDuff.Mode.DST:顯示下層繪制圖片
4.PorterDuff.Mode.SRC_OVER:正常繪制顯示钾怔,上下層繪制疊蓋蒙挑。
5.PorterDuff.Mode.DST_OVER:上下層都顯示。下層居上顯示凝垛。
6.PorterDuff.Mode.SRC_IN:取兩層繪制交集蜓谋。顯示上層。
7.PorterDuff.Mode.DST_IN:取兩層繪制交集剑肯。顯示下層观堂。
8.PorterDuff.Mode.SRC_OUT:上層繪制非交集部分。
9.PorterDuff.Mode.DST_OUT:取下層繪制非交集部分溃睹。
10.PorterDuff.Mode.SRC_ATOP:取下層非交集部分與上層交集部分
11.PorterDuff.Mode.DST_ATOP:取上層非交集部分與下層交集部分
12.PorterDuff.Mode.XOR:異或:去除兩圖層交集部分
13.PorterDuff.Mode.DARKEN:取兩圖層全部區(qū)域胰坟,交集部分顏色加深
14.PorterDuff.Mode.LIGHTEN:取兩圖層全部,點(diǎn)亮交集部分顏色
15.PorterDuff.Mode.MULTIPLY:取兩圖層交集部分疊加后顏色
16.PorterDuff.Mode.SCREEN:取兩圖層全部區(qū)域竞滓,交集部分變?yōu)橥该魃?
Canvas類
Canvas即畫布商佑,其上可以使用Paint畫筆對(duì)象繪制很多東西。
Canvas對(duì)象中可以繪制:
1) drawArc():繪制圓患∮摹礁叔;
2) drawBitmap():繪制Bitmap圖像;
3) drawCircle():繪制圓圈;
4) drawLine():繪制線條讥蔽;
5) drawOval():繪制橢圓冶伞;
6) drawPath():繪制Path路徑;
7) drawPicture():繪制Picture圖片徒爹;
8) drawRect():繪制矩形芋类;
9) drawRoundRect():繪制圓角矩形;
10) drawText():繪制文本胖喳;
11) drawVertices():繪制頂點(diǎn)贮竟。
Canvas對(duì)象的其他方法:
1) canvas.save():把當(dāng)前繪制的圖像保存起來咕别,讓后續(xù)的操作相當(dāng)于是在一個(gè)新圖層上繪制;
2) canvas.restore():把當(dāng)前畫布調(diào)整到上一個(gè)save()之前的狀態(tài)雌贱;
3) canvas.translate(dx, dy):把當(dāng)前畫布的原點(diǎn)移到(dx, dy)點(diǎn),后續(xù)操作都以(dx, dy)點(diǎn)作為參照删掀;
4) canvas.scale(x, y):將當(dāng)前畫布在水平方向上縮放x倍导街,豎直方向上縮放y倍搬瑰;
5) canvas.rotate(angle):將當(dāng)前畫布順時(shí)針旋轉(zhuǎn)angle度。
其他知識(shí)點(diǎn)
- onDetachedFromWindow() 方法調(diào)用時(shí)間
如果你在自己的view中Override了這個(gè)方法艾少。那么我們最關(guān)注的是它什么時(shí)候調(diào)用缚够?
從開發(fā)文檔中我們可以看出鹦赎,onAttachedToWindow是在第一次onDraw前調(diào)用的。也就是我們寫的View在沒有繪制出來時(shí)調(diào)用的古话,但只會(huì)調(diào)用一次。
比如杖们,我們寫狀態(tài)欄中的時(shí)鐘的View摘完,在onAttachedToWindow這方法中做初始化工作婚温,比如注冊(cè)一些廣播等等……
與onAttachedToWindow 相反的則是這個(gè)方法:
onAttachedToWindow() 方法調(diào)用時(shí)間
開發(fā)文檔就簡單的兩句栅螟。也就是我們銷毀View的時(shí)候。我們寫的這個(gè)View不再顯示步绸。
這時(shí)我們就在這個(gè)方法做一些收尾工作吃媒,如:取消廣播注冊(cè)等等。invalidate(); 調(diào)用重繪制布局的時(shí)候只會(huì)調(diào)用onDraw()方法
requestLayout();調(diào)用重繪制布局的時(shí)候只會(huì)調(diào)用 onMeasure OnLayout onDraw 三個(gè)方法