前段時間有人問我關於怎麼繪製不規則圖形的問題。比如,如何像whatsApp那樣繪製的聊天氣泡圖形。在這個系列文章中我們主要來關注一下如何實現不規則圖形效果。
在開始之前,我必須承認我忽略了問我這個問題的這個人。如果您正在閱讀這篇文章,那麼請與我聯絡,我會為你記上一功。感謝您激發我寫這一系列文章的靈感。
我們先從一個簡單的不規則圖形開始:一個帶有圓角的矩形。有必要指出的是,圓角可以使用RoundRectShape Drawable實現(在API2.0裡引入的)。但是,它不能實現之後我們要製作的所有效果,所以我們還是堅持使用自己的方法。
這裡要使用的第一種技術就是我們在Styling Android介紹過的Dynamic Icons——使用Alpha遮罩層實現。
概念很簡單,這裡需要兩張圖片:第一張是我們需要顯示在矩形中的圖片,第二章是需要定義的矩形。然後我們使用一個Porter-Duff Alpha模式來進行圖片結合。這個模式可以讓我們從遮罩層中使用到透明畫素的資訊。
這是我們需要使用到的圖片:
第一張是Betty,這篇文章的模特。第二張是定義圓角的遮罩層,這圖片用綠色的原因是要保證遮罩層中的顏色不會被使用到(我們可不希望在轉換的過程中讓Betty變成綠色)。
程式碼很簡單:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
; html-script: false ] public Bitmap combineImages(Bitmap bgd, Bitmap fg) { Bitmap bmp; int width = bgd.getWidth() > fg.getWidth() ? bgd.getWidth() : fg.getWidth(); int height = bgd.getHeight() > fg.getHeight() ? bgd.getHeight() : fg.getHeight(); bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Paint paint = new Paint(); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)); Canvas canvas = new Canvas(bmp); canvas.drawBitmap(bgd, 0, 0, null); canvas.drawBitmap(fg, 0, 0, paint); return bmp; } |
現在我們就建立了一張匹配了原圖和遮罩層的新圖片。首先就先繪製遮罩層圖片,然後就把可愛的Betty繪製上去,使用一個帶有SRC_ATOP的PorterDuffXFerMode模式的paint物件。這樣就可以使用背景遮罩層的透明畫素,進而就可以準確繪製原圖了。結果就像這樣:
看起來非常不錯,我們可以實現預期的結果了,但是這個方法還有一些問題。
首先,遮罩層的密度必須和原圖一樣,這點我們其實也可以對遮罩層進行縮放處理,但是縮放過度的話也會出現問題的。還有就是,如果原圖和遮罩層的圖比例不一樣的話圓角也會出現變形。
還有一個大問題是,這樣不夠高效。為了實現這個效果,我們需要載入兩張圖片到記憶體中,然後結合成一張新的圖片。如果圖片很大的話,這樣我們就有出現OutOfMemoryError的危險。
雖然這種技術還存在一些問題(比如不規則圖形太複雜的話,用這種技術就有些困難了),但是還有會有解決方案的。這就是我們後面要說的,一種更高效的方式。我們在下一篇文章再見。
這篇文章的所有程式碼在這裡。