自定義View基礎(chǔ) - onMeasure、Paint類笋妥、Canvas

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的多種效果败京,我們可以參考下面一張圖:


image.png

 在使用的時(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è)方法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末氯质,一起剝皮案震驚了整個(gè)濱河市闻察,隨后出現(xiàn)的幾起案子琢锋,更是在濱河造成了極大的恐慌吴超,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,919評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鲸阻,死亡現(xiàn)場離奇詭異跋涣,居然都是意外死亡鸟悴,警方通過查閱死者的電腦和手機(jī)仆潮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拾并,“玉大人嗅义,你說我怎么就攤上這事之碗⊥誓牵” “怎么了博敬?”我有些...
    開封第一講書人閱讀 163,316評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵偏窝,是天一觀的道長。 經(jīng)常有香客問我火窒,道長熏矿,這世上最難降的妖魔是什么缆八? 我笑而不...
    開封第一講書人閱讀 58,294評(píng)論 1 292
  • 正文 為了忘掉前任栏妖,我火速辦了婚禮吊趾,結(jié)果婚禮上论泛,老公的妹妹穿的比我還像新娘屁奏。我一直安慰自己坟瓢,他們只是感情好折联,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評(píng)論 6 390
  • 文/花漫 我一把揭開白布诚镰。 她就那樣靜靜地躺著清笨,像睡著了一般函筋。 火紅的嫁衣襯著肌膚如雪跌帐。 梳的紋絲不亂的頭發(fā)上谨敛,一...
    開封第一講書人閱讀 51,245評(píng)論 1 299
  • 那天脸狸,我揣著相機(jī)與錄音,去河邊找鬼。 笑死吟吝,一個(gè)胖子當(dāng)著我的面吹牛颈娜,可吹牛的內(nèi)容都是我干的官辽。 我是一名探鬼主播萤捆,決...
    沈念sama閱讀 40,120評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼鳖轰,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蝠筑,我...
    開封第一講書人閱讀 38,964評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤什乙,失蹤者是張志新(化名)和其女友劉穎辅愿,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,376評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡削锰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評(píng)論 2 333
  • 正文 我和宋清朗相戀三年磨澡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了稳摄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片厦酬。...
    茶點(diǎn)故事閱讀 39,764評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡昌讲,死狀恐怖短绸,靈堂內(nèi)的尸體忽然破棺而出醋闭,到底是詐尸還是另有隱情证逻,我是刑警寧澤丈咐,帶...
    沈念sama閱讀 35,460評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站歹河,受9級(jí)特大地震影響秸歧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜经备,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評(píng)論 3 327
  • 文/蒙蒙 一傅蹂、第九天 我趴在偏房一處隱蔽的房頂上張望份蝴。 院中可真熱鬧案糙,春花似錦侍筛、人聲如沸匣椰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蠢络,卻和暖如春刹孔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背方库。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評(píng)論 1 269
  • 我被黑心中介騙來泰國打工配喳, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留晴裹,地道東北人只磷。 一個(gè)月前我還...
    沈念sama閱讀 47,819評(píng)論 2 370
  • 正文 我出身青樓元媚,卻偏偏與公主長得像甥角,于是被迫代替她去往敵國和親驴一。 傳聞我的和親對(duì)象是個(gè)殘疾皇子胸懈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容