天天看點

如何優雅的從網絡加載點九圖?如何處理從網絡加載點九的圖

如何處理從網絡加載點九的圖

我們開發Android應用的時候,當需要适配可拉伸的背景,我們會使用.9.png的圖。通常我們是放在res目錄下的,這種方式我們很容易做到。但是如果需要我們去網絡擷取.9的圖該如何做呢?

1 背景

1.1 什麼是點九圖

其實點九圖和我們用的其他格式的圖沒有什麼大的不同,隻不過是在圖檔的四周各增加了1px的純黑(#FF000000)的線進行标記。例如:

如何優雅的從網絡加載點九圖?如何處理從網絡加載點九的圖
标記位置 含義
左-黑線 縱向拉伸區域
上-黑線 橫向拉伸區域
右-黑線 縱向顯示區域
下-黑線 橫向顯示區域

1.2 Android是如何加載點九圖的

當我們将點九圖放在res目錄下,Android不是直接去加載點九圖的,而是在編譯的時候将其轉換成另一種格式,這種格式是将其四周的黑色像素儲存在Bitmap類中的mNinePatchChunk的byte[]數組中,并去掉四周一像素的寬度;在使用的時候,當判斷mNinePatchChunk不為空且為9patchchunk,則将其構造為NinePatchDrawable,否則構造為BitmapDrawable,最終設定給view。是以,最後打包後的點九圖已經不是原來帶黑線的點九圖了。

2 使用方案

2.1 遇到的坑

如果沒做任何處理,當我們從服務端直接拉取點九的圖設定到我們的view上時,發現圖檔并不會拉伸,并且圖檔周圍的黑線也會顯示出來。從上1.2Android加載點九圖的原理可知,之是以出現這種問題,是因為我們少了編譯這一步,是直接拿原始的點九圖設定到view上的,是以才出現問題。 知道錯誤的原因後,我們可以做如下幾種方式處理:

讓産品或者設計師先進行轉換後(轉換工具由開發提供)再上傳到伺服器,這時用戶端再從服務端拉取到的就是編譯處理後的點九圖了

将原始點九圖上傳到一個轉換平台,平台進行轉換後再上傳到伺服器

另外一種是用戶端拿到原始的點九圖後自行處理,根據加載的原理自行構造出NinePatchDrawable,這個過程放到用戶端渲染的時候顯然太耗時,不符合要求 我們以QQ的方案為例(第一種)來讨論實作方案。

2.2 使用方案

先看下總的流程圖:

如何優雅的從網絡加載點九圖?如何處理從網絡加載點九的圖

使用上述方案的注意事項:

  • 步驟2畫黑線必須是純黑色像素,且圖檔的四個角必須為透明像素點,否則Android無法識别,且在步驟3中将無法轉換
  • 步驟3中,可以使用Android SDK自帶工具aapt進行轉換:aapt c -v -S . -C .\output,其中.表示目前目錄,.\output表示目标目錄
  • 步驟4中,上傳過程中不能對轉換後的圖進行壓縮,因為轉換後的點九圖的黑線資訊被儲存到了png圖檔的輔助資料快中,這部分資料在壓縮的過程中會消失,導緻最終用戶端拉取到的圖檔不是點九圖
  • 步驟4中,某些cdn因為省流量,或者其他原因,對圖檔進行壓縮或者轉碼為webp格式,這樣會導緻最終拉取到的圖檔不是點九圖。
  • 步驟8中,需要通過Bitmap建立drawable,如果是使用res目錄下的,Android系統會自動完成,如果是擷取網絡圖檔則需要自己手動建立,如下:
    如何優雅的從網絡加載點九圖?如何處理從網絡加載點九的圖
  • 步驟9中,一定要使用緩存,不然異步加載的過程中,在list中顯示會有問題,跳變很嚴重。

更多Android技術請關注“南京Android部落”公衆号:

如何優雅的從網絡加載點九圖?如何處理從網絡加載點九的圖