自定義控件理解匯總

說到自定義控件,我想說其實我們做Android的,都學過Java基礎,都明白什么是面向對象的思想, 既然有人造了輪子,我們直接拿來用就可以,當然有時間我們還是要研究自定義控件常用的一些類、方法等,然后把別人的自定義控件修改成自己所要的需求。

一、理論基礎篇

1.直接繼承View或者View的子類,View類中沒有提供無參的構造方法,IDE會提醒你聲明一個帶有父類一樣簽名列表的構造方法。

2. 在自定義View的構造方法中必須添加一個AttributeSet類型的簽名來解析這些屬性;否則布局中引用自定義控件的時候會報錯,因為控件要有寬和高的屬性值;

3.在onDraw(Canvas canvas){ }方法實現(xiàn)要畫的東西;這個時候需要畫筆和畫布,重寫這個方法就可以拿到畫布,new 個畫布就可以;

4. 給畫布設置屬性:設置相應的屬性調用setter方法就可以,比如說抗鋸齒(讓畫出來的東西更加圓滑光澤),setAntiAlias(true)就可以;

5. 創(chuàng)建畫筆的時候剛開始用有些人就會直接在onDraw()方法中new ?畫筆,運行后開發(fā)工具會報錯,因為onDraw()方法是一個經常會調用的方法, 調用一次就創(chuàng)建一個畫筆對象,會很占內存,建議在構造方法里面創(chuàng)建;

6.畫筆有了,畫筆的屬性有了,要畫什么東西? 通過畫布對象canvas調用drawXXX()方法,畫相應你要畫的東西;

7. 要注意的是,如果沒有特別說明,設置參數(shù)的單位一般都是px像素;

8. 如果要實現(xiàn)動畫效果,會調用到重繪方法invalidate();

二、深入說明—— 畫筆中設置顏色過濾類ColorFilter

1.set(Paint src) ?--- ?為當前的畫筆設置一個畫筆,就是把一個畫筆的屬性設置copy給我們的畫筆;

2.setAntiAlias(boolean aa) -- ?一般圓形要設置抗鋸齒,像矩形這種一般就不用;

3.setColorFilter(ColorFilter filter) --- 設置顏色過濾,獲取我們想要的色彩結果;ColorFilter有三個子類LightingColorFilter、PortDuffColorFilter、ColorMatrixColorFilter。現(xiàn)在找工作那么難,一定要深究;

4.ColorMatrixColorFilter-- 色彩矩陣顏色過濾器。 在Android中圖片是以RGBA像素點的形式加載到內存中,修改這些像素信息需要一個叫做ColorMatrix類支持,其定義了一個4x5的float[]類型的矩陣;第一行表示R(紅色)的向量,第二行表示G(綠色)的向量,第三表示B(藍色)的向量,最后一行表示A(透明度)的向量。1代表保持原圖的RGB值,其取值范圍在0.0F--2.0F之間。每一行的第5列代表偏移值。 單個顏色的時候我們直接用setColor()方法就行,如果是一張圖片的時候我們就要用到矩陣這個東西。

5.LightingColorFilter ?-- ?光照顏色過濾,該類有且只有一個構造方法:LightingColorFilter?(intmul,intadd);

這個方法非常非常地簡單!mul全稱是colorMultiply意為色彩倍增,而add全稱是colorAdd意為色彩添加,這兩個值都是16進制的色彩值0xAARRGGBB。當LightingColorFilter(0xFFFFFFFF, 0x00000000)的時候原圖是不會有任何改變的,如果我們想增加紅色的值,那么LightingColorFilter(0xFFFFFFFF, 0x00XX0000)就好,其中XX取值為00至FF。那么這個方法有什么存在的意義呢?存在必定合理,這個方法存在一定是有它可用之處的,前些天有個盆友在群里問點擊一個圖片如何直接改變它的顏色而不是為他多準備另一張點擊效果的圖片,這種情況下該方法就派上用場了!

6.PortDuffColorFilter---PorterDuffColorFilter跟LightingColorFilter一樣,只有一個構造方法:PorterDuffColorFilter(intcolor,?PorterDuff.Mode?mode),這個構造方法也接受兩個值,一個是16進制表示的顏色值這個很好理解,而另一個是PorterDuff內部類Mode中的一個常量值,這個值表示混合模式。那么什么是混合模式呢?混合混合必定是有兩種東西混才行,第一種就是我們設置的color值而第二種當然就是我們畫布上的元素了!,比如這里我們把Color的值設為紅色,而模式設為PorterDuff.Mode.DARKEN變暗。

三、深入說明—— 畫筆中設置混合模式類Xfermode

1.Xfermode國外有大神稱之為過渡模式,這種翻譯比較貼切但恐怕不易理解,大家也可以直接稱之為圖像混合模式,因為所謂的“過渡”其實就是圖像混合的一種,這個方法跟我們上面講到的setColorFilter蠻相似的,首先它與set一樣沒有公開的實現(xiàn)的方法:同理可得其必然有一定的子類去實現(xiàn)一些方法供我們使用,查看API文檔發(fā)現(xiàn)其果然有三個子類:AvoidXfermode, PixelXorXfermode和PorterDuffXfermode,這三個子類實現(xiàn)的功能要比setColorFilter的三個子類復雜得多。

2.AvoidXfermode--首先我要告訴大家的是這個API因為不支持硬件加速在API 16已經過時了(大家可以在HardwareAccel查看那些方法不支持硬件加速)……如果想在高于API 16的機子上測試這玩意,必須現(xiàn)在應用或手機設置中關閉硬件加速,在應用中我們可以通過在AndroidManifest.xml文件中設置application節(jié)點下的android:hardwareAccelerated屬性為false來關閉硬件加速:-- ?現(xiàn)在不用了,就不研究了。

3.PixelXorXfermode--與AvoidXfermode一樣也在API 16過時了,不研究。

4.PorterDuffXfermode,該類同樣有且只有一個含參的構造方法PorterDuffXfermode(PorterDuff.Mode mode),這個PorterDuff.Mode大家看后是否會有些面熟,它跟上面我們講ColorFilter時候用到的PorterDuff.Mode是一樣的!麻雀雖小五臟俱全,雖說構造方法的簽名列表里只有一個PorterDuff.Mode的參數(shù),但是它可以實現(xiàn)很多酷斃的圖形效果!!而PorterDuffXfermode就是圖形混合模式的意思。對于PorterDuff.Mode mode在API中Android為我們提供了18種。

四、深入說明 -- 字體測量類?FontMetrics?

1.而它里面呢就定義了top,ascent,descent,bottom,leading五個成員變量其他什么也沒有:

這五個成員變量除了top和bottom我們較熟悉外其余三個都很陌生是做什么用的呢?首先我給大家看張圖:

這張圖很簡單但是也很扼要的說明了top,ascent,descent,bottom,leading這五個參數(shù)。首先我們要知道Baseline基線,在Android中,文字的繪制都是從Baseline處開始的,Baseline往上至字符最高處的距離我們稱之為ascent(上坡度),Baseline往下至字符最底處的距離我們稱之為descent(下坡度),而leading(行間距)則表示上一行字符的descent到該行字符的ascent之間的距離,top和bottom文檔描述地很模糊,其實這里我們可以借鑒一下TextView對文本的繪制,TextView在繪制文本的時候總會在文本的最外層留出一些內邊距,為什么要這樣做?因為TextView在繪制文本的時候考慮到了類似讀音符號,可能大家很久沒寫過拼音了已經忘了什么叫讀音符號了吧……下圖中的A上面的符號就是一個拉丁文的類似讀音符號的東西:
注:Baseline上方的值為負,下方的值為正

就是說我們FontMetrics的這些值跟我們要繪制什么文本是無關的,而僅與繪制文本Paint的size和typeface有關我們來分別更改這兩個值看看:mPaint.setTextSize(70);

如圖所示所有值都改變了,我們再為Paint設置一個typeface:mPaint.setTypeface(Typeface.SERIF);

如果我現(xiàn)在字體居中,單純是canvas.getWidth() /2和canvas.getHeight() /2 是不夠準確的,必須用到上面的五個參數(shù)減去相應的距離:

實際情況中有很多不同的需求不如靠近某個區(qū)域離某個區(qū)域需要多少距離等等,熟練地去學會計算文本測繪中的各個值就顯得很有必要了!

五、深入說明 -- 文字畫筆TextPaint

2. Paint有一個唯一的子類TextPaint就是專門為文本繪制量身定做的“筆”,而這支筆就如API所描述的那樣能夠在繪制時為文本添加一些額外的信息,這些信息包括:baselineShift,bgColor,density,drawableState,linkColor等等。?

換行繪制?使用StaticLayout結合TextPaint實現(xiàn)換行,StaticLayout是android.text.Layout的一個子類,很明顯它也是為文本處理量身定做的,其內部實現(xiàn)了文本繪制換行的處理。

六、深入說明 -- 模糊遮罩濾鏡類MaskFilter

1.setMaskFilter(MaskFilter maskfilter) ?

MaskFilter類中沒有任何實現(xiàn)方法,而它有兩個子類BlurMaskFilter和EmbossMaskFilter,前者為模糊遮罩濾鏡(比起稱之為過濾器哥更喜歡稱之為濾鏡)而后者為浮雕遮罩濾鏡,我們先來看第一個:BlurMaskFilter--? 已經過時, 如果你想在Android系統(tǒng)Api大于15(Android系統(tǒng)4.0)以上的,不支持應用硬件加速,必須關閉硬件加速,在清單文件的Application節(jié)點下面直接添加android:hardwareAccelerated為false來關閉的,或者直接view的初始化畫筆的方法里面:setLayerType(LAYER_TYPE_SOFTWARE, null)。

2.EmbossMaskFilter -- 他可以實現(xiàn)一種類似浮雕的效果,說白了就是讓你繪制的圖像感覺像是從屏幕中“凸”起來更有立體感一樣(在設計軟件中類似的效果稱之為斜面浮雕),比較少用。

七、深入說明 -- 路徑效果類PathEffect

1.setPathEffect(PathEffect effect),PathEffect見文知意很明顯就是路徑效果的意思~~那這玩意肯定跟路徑Path有關咯?那是必須的撒!PathEffect跟上面的很多類一樣沒有具體的實現(xiàn),但是其有六個子類,這六個子類分別可以實現(xiàn)不同的路徑效果:

分別是:沒有PathEffect、CornerPathEffect、DiscretePathEffect、DashPathEffect、PathDashPathEffect、ComposePathEffect、SumPathEffect

2.CornerPathEffect,當我們不設置路徑效果的時候路徑的默認效果就如上圖第一條線那樣直的轉折生硬;而CornerPathEffect則可以將路徑的轉角變得圓滑如圖第二條線的效果,這六種路徑效果類都有且只有一個含參的構造方法,CornerPathEffect的構造方法只接受一個參數(shù)radius,意思就是轉角處的圓滑程度,我們嘗試更改一下上面的代碼:mEffects[1] =newCornerPathEffect(50);

3.DiscretePathEffect離散路徑效果相對來說則稍微復雜點,其會在路徑上繪制很多“雜點”的突出來模擬一種類似生銹鐵絲的效果如上圖第三條線,其構造方法有兩個參數(shù),第一個呢指定這些突出的“雜點”的密度,值越小雜點越密集,第二個參數(shù)呢則是“雜點”突出的大小,值越大突出的距離越大反之反之;

4.DashPathEffect的效果相對與上面兩種路徑效果來說要略顯復雜,其雖說也是包含了兩個參數(shù),但是第一個參數(shù)是一個浮點型的數(shù)組,那這個數(shù)組有什么意義呢?其實是這樣的,我們在定義該參數(shù)的時候只要浮點型數(shù)組中元素個數(shù)大于等于2即可,也就是說上面我們的代碼可以寫成這樣的:mEffects[3] =newDashPathEffect(newfloat[] {20,10}, mPhase); 從圖中我們可以看到我們之前的那種線條變成了一長一短的間隔線條,而float[] {20, 10}的偶數(shù)參數(shù)20(注意數(shù)組下標是從0開始哦)定義了我們第一條實線的長度,而奇數(shù)參數(shù)10則表示第一條虛線的長度,如果此時數(shù)組后面不再有數(shù)據(jù)則重復第一個數(shù)以此往復循環(huán),比如我們20,10后沒數(shù)了,那么整條線就成了[20,10,20,10,20,10…………………………]這么一個狀態(tài),而DashPathEffect的第二個參數(shù)我稱之為偏移值,動態(tài)改變其值會讓路徑產生動畫的效果;

5.PathDashPathEffect和DashPathEffect是類似的,不同的是PathDashPathEffect可以讓我們自己定義路徑虛線的樣式,比如我們將其換成一個個小圓組成的虛線。

6.ComposePathEffect和SumPathEffect都可以用來組合兩種路徑效果,唯一不同的是組合的方式,ComposePathEffect(PathEffect outerpe, PathEffect innerpe)會先將路徑變成innerpe的效果,再去復合outerpe的路徑效果,即:outerpe(innerpe(Path));而SumPathEffect(PathEffect first, PathEffect second)則會把兩種路徑效果加起來再作用于路徑。

八、深入說明 -- 著色器Shader

1.setShader(Shader shader),這五個Shader里最異類的是BitmapShader,因為只有它是允許我們載入一張圖片來給圖像著色,那我們還是先來看看這個怪胎吧。構造方法BitmapShader (Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY);重點講解第二個參數(shù),CLAMP--邊緣拉伸; MIRROR -- 鏡像;REPEAT -- 重復;

2.LinearGradient -- 線性漸變,顧名思義這錘子玩意就是來畫漸變的,實際上Shader的五個子類中除了上面我們說的那個怪胎,還有個變形金剛ComposeShader外其余三個都是漸變只是效果不同而已。兩個構造方法:LinearGradient(floatx0,floaty0,floatx1,floaty1,intcolor0,intcolor1, Shader.TileMode tile),這是LinearGradient最簡單的一個構造方法,參數(shù)雖多其實很好理解x0和y0表示漸變的起點坐標而x1和y1則表示漸變的終點坐標,這兩點都是相對于屏幕坐標系而言的,而color0和color1則表示起點的顏色和終點的顏色;僅僅兩種顏色的漸變根本無法滿足我們身體的欲望,太單調乏味!我們是不是可以定義多種顏色漸變呢?答案是必須的,LinearGradient的另一個構造方法LinearGradient(floatx0,floaty0,floatx1,floaty1,int[] colors,float[] positions, Shader.TileMode tile)。

3.SweepGradient---的意思是梯度漸變,也稱之為掃描式漸變,因為其效果有點類似雷達的掃描效果,他也有兩個構造方法:SweepGradient(floatcx,floatcy,intcolor0,intcolor1);和mPaint.setShader(newSweepGradient(screenX, screenY,newint[] { Color.GREEN, Color.WHITE, Color.GREEN },null))。

4.RadialGradient -- 徑向漸變,徑向漸變說的簡單點就是個圓形中心向四周漸變的效果,他也一樣有兩個構造方法;

5.ComposeShader -- 就是組合Shader的意思,顧名思義就是兩個Shader組合在一起作為一個新Shader,兩個構造方法:ComposeShader (Shader shaderA, Shader shaderB, Xfermode mode);ComposeShader?(Shader?shaderA,?Shader?shaderB,?PorterDuff.Mode?mode);

二、自定義控件

Android自定義控件總結

三、view和viewgroup的區(qū)別?

View與ViewGroup有什么區(qū)別?

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容