目前在Android中通知的使用仍是很常見的,爲了作版本兼容,經常使用兼容包NotificationCompat.Builder和 Notification.Builder。html
NotificationCompat.Builder位於v4擴展包內(version 4 Support Library)java
Notification.Builder在Android 3.0 開始引入(API level 11).android
最近在Android5.0設備上發現一個問題:通知圖標忽然變成了白色的方塊而不是代碼中設置的icon。程序員
細讀開發者文檔其實也能夠發現一些線索,雖然筆者是直接查的源碼發現的問題緣由。http://developer.android.com/design/patterns/notifications.html 一文的Use distinct icons部分介紹了幾點關於通知的建議,其中的有兩點是建議開發者不要作的行爲。api
Don't Place any additional alpha (dimming or fading) into your small icons and action icons; they can have anti-aliased edges, but because Android uses these icons as masks (that is, only the alpha channel is used), the image should generally be drawn at full opacity. Don't Use color to distinguish your app from others. Notification icons should only be a white-on-transparent background image.
簡單的說就是5.0後Android官方建議不要爲通知的圖標添加任何額外的透明度,漸變色,不要企圖用顏色將通知圖標與其餘應用,好比系統應用,應用的通知圖標只能是在透明的背景上有白色的圖案。
至於緣由,文檔並無細說,只是提到5.0系統將會在底層處理圖標,想知怎麼處理的能夠參考Android SDK API level 21後的Notificaiton源碼,裏面寫的較詳細。
app
結合文檔提供的圖片示例,應該能夠理解。
若是不遵循建議那麼有很大概率是會出上文提到問題的,爲何不是別然出問題呢?
這還依賴於代碼編譯的版本,根據嘗試,目前api 21之後編譯會出問題,20及之前的版本編譯不會出問題。因此解決問題比較簡單粗暴的方案是用20及更早的版本編譯代碼。可是要測底解決問題,仍是得遵循文檔指導,及重新設計通知的圖標以符合要求。ide
下面看一下到底21的Android源碼裏面作了什麼操做會致使通知的圖標通通變白色。
Notification.java源碼分析
private RemoteViews applyStandardTemplate(int resId, boolean hasProgress) { //... if (mLargeIcon != null) { contentView.setImageViewBitmap(R.id.icon, mLargeIcon); processLargeLegacyIcon(mLargeIcon, contentView); contentView.setImageViewResource(R.id.right_icon, mSmallIcon); contentView.setViewVisibility(R.id.right_icon, View.VISIBLE); processSmallRightIcon(mSmallIcon, contentView); } else { // small icon at left contentView.setImageViewResource(R.id.icon, mSmallIcon); contentView.setViewVisibility(R.id.icon, View.VISIBLE); processSmallIconAsLarge(mSmallIcon, contentView); } //...}
/** * Recolor small icons when used in the R.id.right_icon slot. */ private void processSmallRightIcon(int smallIconDrawableId, RemoteViews contentView) { if (!isLegacy() || mColorUtil.isGrayscaleIcon(mContext, smallIconDrawableId)) { contentView.setDrawableParameters(R.id.right_icon, false, -1, 0xFFFFFFFF, PorterDuff.Mode.SRC_ATOP, -1); contentView.setInt(R.id.right_icon, "setBackgroundResource", R.drawable.notification_icon_legacy_bg); contentView.setDrawableParameters( R.id.right_icon, true, -1, resolveColor(), PorterDuff.Mode.SRC_ATOP, -1); } }
這裏我截取了兩段比較關鍵的代碼,在用NotificationCompat.Builder實例化咱們的通知後,最終須要將各類圖標,參數配置,應用到通知視圖上面。能夠看到若是咱們只設置smallIcon而不設置largeIcon也是能夠的,此時直接將small做爲大圖標設置給左側的id爲R.id.icon的ImageView。要注意的事通常狀況下都不能夠不設置smallIcon,不然通知沒法正常顯示出來。
processSmallIconAsLarge方法裏面負責將咱們設置的smallIcon二次處理,也就是這裏會改變咱們最終看到的通知圖標,包括頂部狀態欄和下拉顯示的小圖標。測試
///////////////////////////////////2018-5-9 第二次編輯///////////////////////////////////////////////////ui
對於通知欄的使用,Android各個版本其實都有比較大的調整,包括即將發佈的Android 7.0版本,通知欄功能上又要有大動做。那麼新版本的通知欄API沒法兼容老系統這就會是一個很頭疼的問題。
爲此Android在appcompat-v7庫中提供了一個NotificationCompat類來處理新老版本的兼容問題,咱們在編寫通知功能時都使用NotificationCompat這個類來實現,appcompat-v7庫就會自動幫咱們作好全部系統版本的兼容性處理了。一段基本的觸發通知代碼以下所示:
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); NotificationCompat.Builder builder = new NotificationCompat.Builder(context); Notification notification = builder .setContentTitle("這是通知標題") .setContentText("這是通知內容") .setWhen(System.currentTimeMillis()) .setSmallIcon(R.mipmap.ic_launcher) .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)) .build(); manager.notify(1, notification);
能夠看到,這裏只是把咱們平時使用的Notification.Builder改爲了NotificationCompat.Builder而已,其餘用法都是如出一轍的,這樣咱們的通知就具有各類Android版本的兼容性了。
注意看一下咱們給通知設置的圖標,一個小圖標、一個大圖標,都是使用的R.mipmap.ic_launcher這張圖。其實不少app都使用的這種作法,即直接拿應用程序的icon來做爲通知的圖標,好像這樣看上去也挺合理的。
如今我使用Android 6.0系統的Nexus 5手機運行這個程序,並觸發上面那段通知邏輯,效果如圖下圖所示:
能夠看到,通知欄上彈出了一個通知圖標。而後咱們將通知欄下拉展開,效果以下圖所示:
效果好像還不錯的樣子。但實際上,我如今是將項目的targetSdkVersion指定成了21如下,即低於5.0系統。若是將targetSdkVersion指定成21或者更高的話,結果可能就不樂觀了:
defaultConfig { .... targetSdkVersion 23 }
這裏咱們將targetSdkVersion指定成了23,而後從新運行程序並觸發圖標邏輯,效果以下圖所示:
恩?這是什麼鬼,怎麼通知圖標變成白白的一個圓了。下拉以後的大圖效果以下:
好像下拉以後的大圖還算正常,不過大圖的右下角也有一個白白的圓。
這究竟是爲何呢?實際上,Android從5.0系統開始,對於通知欄圖標的設計進行了修改。如今Google要求,全部應用程序的通知欄圖標,應該只使用alpha圖層來進行繪製,而不該該包括RGB圖層。
說的好像很玄乎,什麼叫做只使用alpha圖層來進行繪製呢?其實通俗點來說,就是讓咱們的通知欄圖標不要帶顏色就能夠了。
恩?不帶顏色!那圖標還怎麼設計?但這就不是咱們程序員應該考慮的問題了,而是應該交給項目的UI設計師來想辦法,但咱們須要將這個設計需求清楚地告訴設計師,由於他們一般並不知道Google的各類標準和要求。
那麼咱們來參考一下別的程序都是怎麼設計通知欄圖標的,這是支付寶的通知欄圖標:
下拉通知以後的效果是這樣的:
而後再看一下網易新聞的通知欄圖標:
下拉通知以後的效果是這樣的:
能夠看出,它們的通知欄小圖都是沒有RGB色的,圖標是隻有白色一種顏色,而後藉助alpha圖層來繪製出一個logo的樣式。
所以,按着這種設計要求,我將項目的通知欄圖標改爲了這個樣子:
這張圖只用於替換通知的小圖部分,大圖仍然仍是用原來的那樣圖就能夠了。如今從新運行一下程序,效果以下圖所示:
這樣看上去效果就好多了吧?而後下拉通知欄以後的效果以下圖所示:
這裏咱們來仔細觀察一下這個下拉後的大圖,其實前面你們應該也已經注意到了,只不過一直沒提,在大圖標的右下角,還有一個比較小的圓圈,在這個圓圈中嵌套着咱們設置的小圖標。
這個功能是系統自動附加的一個功能,並不須要咱們進行任何的代碼設置,能夠觀察一下,支付寶、網易新聞也都是有這個功能的。可是若是咱們再看仔細一點,你會發現網易的圖標更好看一些,由於系統給右下角的這個小圓圈默認是設置成灰色的,和咱們的總體色調並不搭配,而網易則將這個小圓圈改爲了紅色,所以整體視覺效果更好。
那麼怎樣修改這個小圓圈的顏色呢?其實很是簡單,只須要在NotificationCompat.Builder中再多連綴一個setColor()方法就能夠了,以下所示:
Notification notification = builder ...... .setColor(Color.parseColor("#EAA935")) .build();
如今從新運行一下程序,通知欄大圖的具體效果以下圖所示:
怎麼樣,如今的效果是否是更棒了?可是這裏我還要給你們提個醒,上面的功能我使用Nexus手機和三星手機都測試過,結果都是正常的,可是使用小米手機測試就比較無語了,MIUI系統直接無視咱們設置的大圖和小圖,一概使用應用程序的icon來做爲通知欄圖標,因此若是你是使用的小米手機,就測試不出來上述的各類效果了。其餘手機的兼容性我尚未試過,不過無論怎麼樣,咱們的代碼都是要這麼寫的,至於那些定製過的系統該如何去解析展現,那是這些第三方廠商的事情,畢竟咱們程序員也是控制不了的。
固然,若是你手上只有小米手機的話,也不要絕望,仍是可使用Android模擬器來測試這個功能的。
本文出自郭霖的博客
做者: 郭霖
連接:http://www.imooc.com/article/8175
來源:慕課網
本文原創發佈於慕課網 ,轉載請註明出處,謝謝合做
http://developer.android.com/design/patterns/notifications.html
http://developer.android.com/guide/topics/ui/notifiers/notifications.html
做者:小文字