高級畫布繪圖(3) DashPathEffect 可以使用DashPathEffect來創(chuàng)建一個(gè)虛線的輪廓(短橫線/小圓點(diǎn)),而不是使用實(shí)線。你還可以指定任意的虛/實(shí)線段的重復(fù)模式。
DiscretePathEffect 與DashPathEffect相似,但是添加了隨機(jī)性。當(dāng)繪制它的時(shí)候,需要指定每一段的長度和與原始路徑的偏離度。
PathDashPathEffect 這種效果可以定義一個(gè)新的形狀(路徑)并將其用作原始路徑的輪廓標(biāo)記。
下面的效果可以在一個(gè)Paint中組合使用多個(gè)Path Effect。
SumPathEffect 順序地在一條路徑中添加兩種效果,這樣每一種效果都可以應(yīng)用到原始路徑中,而且兩種結(jié)果可以結(jié)合起來。
ComposePathEffect 將兩種效果組合起來應(yīng)用,先使用第一種效果,然后在這種效果的基礎(chǔ)上應(yīng)用第二種效果。
對象形狀的PathEffect的改變會(huì)影響到形狀的區(qū)域。這就能夠保證應(yīng)用到相同形狀的填充效果將會(huì)繪制到新的邊界中。
使用setPathEffect方法可以把PathEffect應(yīng)用到Paint對象中,如下所示:
- borderPaint.setPathEffect(new CornerPathEffect(5));
PathEffect API示例給出了如何應(yīng)用每一種效果的指導(dǎo)說明。
修改Xfermode
可以通過修改Paint的Xfermode來影響在Canvas已有的圖像上面繪制新的顏色的方式。
在正常的情況下,在已有的圖像上繪圖將會(huì)在其上面添加一層新的形狀。如果新的Paint是完全不透明的,那么它將完全遮擋住下面的Paint;如果它是部分透明的,那么它將會(huì)被染上下面的顏色。
下面的Xfermode子類可以改變這種行為:
AvoidXfermode 指定了一個(gè)顏色和容差,強(qiáng)制Paint避免在它上面繪圖(或者只在它上面繪圖)。
PixelXorXfermode 當(dāng)覆蓋已有的顏色時(shí),應(yīng)用一個(gè)簡單的像素XOR操作。
PorterDuffXfermode 這是一個(gè)非常強(qiáng)大的轉(zhuǎn)換模式,使用它,可以使用圖像合成的16條Porter-Duff規(guī)則的任意一條來控制Paint如何與已有的Canvas圖像進(jìn)行交互。
要應(yīng)用轉(zhuǎn)換模式,可以使用setXferMode方法,如下所示:
- AvoidXfermode avoid = new AvoidXfermode(Color.BLUE, 10, AvoidXfermode.Mode. AVOID);
- borderPen.setXfermode(avoid);
3. 使用抗鋸齒效果提高Paint質(zhì)量
在繪制一個(gè)新的Paint對象時(shí),可以通過傳遞給它一些標(biāo)記來影響它被渲染的方式。ANTI_ALIAS_FLAG是其中一種很有趣的標(biāo)記,它可以保證在繪制斜線的時(shí)候使用抗鋸齒效果來平滑該斜線的外觀。
在繪制文本的時(shí)候,抗鋸齒效果尤為重要,因?yàn)榻?jīng)過抗鋸齒效果處理之后的文本非常容易閱讀。要?jiǎng)?chuàng)建更加平滑的文本效果,可以應(yīng)用SUBPIXEL_TEXT_FLAG,它將會(huì)應(yīng)用子像素抗鋸齒效果。
也可以手工地使用setSubpixelText和setAntiAlias方法來設(shè)置這些標(biāo)記,如下所示:
- myPaint.setSubpixelText(true);
- myPaint.setAntiAlias(true);
4. 2D圖形的硬件加速
在當(dāng)前這個(gè)到處都是2D圖形愛好者的時(shí)代,Android允許你使用硬件加速來渲染你的應(yīng)用程序。
如果設(shè)備可以使用硬件加速,那么通過設(shè)置這個(gè)標(biāo)記可以讓活動(dòng)中的每一個(gè)View都能使用硬件渲染。盡管減少了系統(tǒng)處理程序的負(fù)載,但在極大地提高了圖像處理速度的同時(shí),硬件加速也帶來了相應(yīng)的負(fù)面效果。
使用requestWindowFeature方法,可以在你的活動(dòng)中應(yīng)用Window.FEATURE_OPENGL標(biāo)記來打開硬件加速,如下所示:
- myActivity.requestWindowFeature(Window.FEATURE_OPENGL);
遺憾的是,天上不會(huì)掉餡餅,這次也不例外。
并不是Android中所有的2D繪圖基本圖形都被硬件支持(特別是前面描述的大部分PathEffect)。
與此同時(shí),由于整個(gè)活動(dòng)實(shí)際上是作為一個(gè)Canvas進(jìn)行渲染的,所以對任何View的無效請求都將會(huì)導(dǎo)致整個(gè)活動(dòng)被重新繪制。
5. Canvas繪圖最佳實(shí)踐經(jīng)驗(yàn)
2D自繪操作是非常耗費(fèi)處理程序資源的;低效的繪圖方法會(huì)阻塞GUI線程,并且會(huì)對應(yīng)用程序的響應(yīng)造成不利的影響。對于那些只有一個(gè)處理程序的資源受限的環(huán)境來說,這一點(diǎn)就更加現(xiàn)實(shí)了。
這里需要注意onDraw方法的資源消耗以及CPU周期的耗費(fèi),這樣才能保證不會(huì)把一個(gè)看起來很吸引人的應(yīng)用程序變得完全沒有響應(yīng)。
目前有很多技術(shù)可以幫助將與自繪控件相關(guān)的資源消耗最小化。我們關(guān)心的不是一般的原則,而是某些Android特定的注意事項(xiàng),從而保證你可以創(chuàng)建外觀時(shí)尚、而且能夠保持交互的活動(dòng)(注意,以下這個(gè)列表并不完整):
考慮硬件加速 OpenGL硬件加速對2D圖形的支持是非常好的,所以你總是應(yīng)該考慮它是否適合你的活動(dòng)。另一種比較優(yōu)秀的方法是只用一個(gè)單獨(dú)的View和迅速的、耗時(shí)的更新來組成活動(dòng)。一定要保證你使用的基本圖形能夠被硬件支持。
考慮大小和方向 當(dāng)在設(shè)計(jì)View和布局的時(shí)候,一定要保證考慮(和測試)它們在不同的分辨率和大小下的外觀。
只創(chuàng)建一次靜態(tài)對象 在Android中對象的創(chuàng)建是相當(dāng)昂貴的。因此,在可能的地方,應(yīng)用只創(chuàng)建一次像Paint對象、Path和Shader這樣的繪圖對象,而不是在View每次無效的時(shí)候都重新創(chuàng)建它們。
記住onDraw是很消耗資源的 執(zhí)行onDraw方法是很消耗資源的處理,它會(huì)強(qiáng)制Android執(zhí)行多個(gè)圖片組合和位圖構(gòu)建操作。下面有幾點(diǎn)建議可以讓你修改Canvas的外觀,而不用重新繪制它:
使用Canvas轉(zhuǎn)換 可以使用像rotate和translate這樣的轉(zhuǎn)換,來簡化Canvas中元素復(fù)雜的相關(guān)位置。例如,相比放置和旋轉(zhuǎn)一個(gè)表盤周圍的每一個(gè)文本元素,你可以簡單地將canvas旋轉(zhuǎn)22.5?,然后在相同的位置繪制文本。
使用動(dòng)畫 可以考慮使用動(dòng)畫來執(zhí)行View的預(yù)設(shè)置的轉(zhuǎn)換,而不是手動(dòng)地重新繪制它。在活動(dòng)的View中可以執(zhí)行縮放、旋轉(zhuǎn)和轉(zhuǎn)換動(dòng)畫,并可以提供一種能夠有效利用資源的方式來提供縮放、旋轉(zhuǎn)或者抖動(dòng)效果。
考慮使用位圖和9 Patch 如果View使用了靜態(tài)背景,那么你應(yīng)該考慮使用一個(gè)圖片,如位圖或者9 patch,而不是手動(dòng)地重新繪制。