Android 自定義通知欄實現資料總結

Android3.0以上版本支持應用自定義通知欄,使用RemoteViews作爲自定義通知欄的展示界面類(該類不繼承View)。具體實現在網上有很多,但絕大部分都不全面,開發中遇到了不少問題,記錄下來,以備後用。

 

一、ROM版本問題

按鈕點擊操作僅支持3.0及以上版本,3.0以下的只能展示界面,裏面定義的按鈕無法觸發;

 

二、自定義通知欄實現方案

NotificationCompat.Builder mBuilder = new Builder(context);
        RemoteViews mRemoteViews = new RemoteViews(context.getPackageName(), param.layoutRes);
        
        mRemoteViews.setTextViewText(R.id.txtView_notify_bar_title,
                param.title);
        mRemoteViews.setTextColor(R.id.txtView_notify_bar_title, 
                NotificationController.newInstance(context).getDefNotificationTitleColor());
        
        mRemoteViews.setTextViewText(R.id.txtView_notify_bar_content,
                param.content);
        mRemoteViews.setTextColor(R.id.txtView_notify_bar_content, 
                NotificationController.getInstance().getDefNotificationContentColor());
        
        showNotifyButtons(context, param, mRemoteViews);
        
        Intent contentIntent = new Intent(context, NotificationService.class);
        contentIntent.setAction(ACTION_CLICK_NOTIFY_BAR_NOTICE);
        contentIntent.putExtra(PARAM_ID, param.id);
        PendingIntent contentPi = PendingIntent.getService(context, param.id,
                contentIntent, PendingIntent.FLAG_CANCEL_CURRENT);

        // 清除消息事件
        Intent deleteIntent = new Intent(context, NotificationService.class);
        deleteIntent.setAction(ACTION_CLEAR_NOTIFY_BAR_NOTICE);
        deleteIntent.putExtra(PARAM_ID, param.id);
        PendingIntent deletePi = PendingIntent.getService(context, param.id,
                deleteIntent, PendingIntent.FLAG_CANCEL_CURRENT);
        mBuilder.setSmallIcon(R.drawable.ico_app)
                .setContentTitle(param.title)
                .setContentText(param.content)
                .setTicker(param.content)
                .setContentIntent(contentPi)
                .setOngoing(false)
                .setDeleteIntent(deletePi)
                .setWhen(System.currentTimeMillis())
                .setLights(Color.GREEN, 300, 3000);
        if(Environment.getOSVersionCode() >= 11 
                && hasButton(param)) {
            mBuilder.setContent(mRemoteViews);
        }
        Notification notify = mBuilder.build();

        notify.flags |= param.flag;
        return notify;

RemoteViews封裝了很多類似View的操作方法,如setTextViewText、setTextColor、setViewVisibility、setOnClickPendingIntent等方法,具體參數都需要int型的ViewId和View的相關參數,指明對那個View的參數進行設置。

三、 通知欄背景色問題


在應用上集成自定義通知欄後,發現不管怎麼設置佈局背景色爲透明,都無法和系統風格保持一致。最終定位發現是AndroidManifest.xml 中

 <uses-sdk android:minSdkVersion="8" />

設置導致默認targetSdkVersion也是8導致的。改爲

<strong> <uses-sdk android:minSdkVersion="8" 
        android:targetSdkVersion="9</strong>及以上<strong>"/></strong>

四、點擊通知欄按鈕收起通知欄

自定義的通知欄按鈕被點擊可以觸發事件,但是是無法自動收起的。在點擊操作觸發時可使用以下代碼收起通知欄:

/**
     * Collapse status panel
     * 
     * @param context
     *            the context used to fetch status bar manager
     */
    private static void collapseStatusBar(Context context) {
        try {
            Object statusBarManager = context.getSystemService("statusbar");
            Method collapse;
            if (Environment.getOSVersionCode() <= 16) {
                collapse = statusBarManager.getClass().getMethod("collapse");
            } else {
                collapse = statusBarManager.getClass().getMethod(
                        "collapsePanels");
            }
            collapse.invoke(statusBarManager);
        } catch (Exception ex) {
            DebugLog.d(TAG, "collapseStatusBar() ", ex);
        }
    }

五、通知欄文字顏色

    1、 自定義樣式方法:

    Android 2.3及以上通知欄的字體顏色與2.2以下的取法不同。在styles.xml中增加兩個樣式:

<style name="NotificationText">
        <item name="android:textColor">?android:attr/textColorPrimary</item>
    </style>

    <style name="NotificationTitle">
        <item name="android:textColor">?android:attr/textColorPrimary</item>
        <item name="android:textStyle">bold</item>
    </style>

在res目錄新建values-v9文件夾,在該文件中新建styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="NotificationText" parent="android:TextAppearance.StatusBar.EventContent" />
    <style name="NotificationTitle" parent="android:TextAppearance.StatusBar.EventContent.Title" />
</resources>

values-v9意味着API 9以上所有版本都取這裏面的定製style作爲屬性。

接着對TextView應用樣式即可。

2、 動態讀值方法

private void getNotificationColor() {
		try {
			Notification ntf = new Notification();
			ntf.setLatestEventInfo(mContext, TEST_NOTIFICATION_TITLE, TEST_NOTIFICATION_CONTENT, null);

			LinearLayout group = new LinearLayout(mContext);
			ViewGroup gp = (ViewGroup) ntf.contentView.apply(mContext, group);
			final int count = gp.getChildCount();
	        for (int i = 0; i < count; ++i) {
	            if (gp.getChildAt(i) instanceof TextView) {
	                final TextView text = (TextView) gp.getChildAt(i);
	                final String szText = text.getText().toString();
	                if (TEST_NOTIFICATION_TITLE.equals(szText)) {
	                    mDefTitleColor = text.getTextColors().getDefaultColor();
	                } else if (TEST_NOTIFICATION_CONTENT.equals(szText)) {
	                    mDefContentColor = text.getTextColors().getDefaultColor();
	                }
	            } else if (gp.getChildAt(i) instanceof ViewGroup) {
	                getTextColor((ViewGroup) gp.getChildAt(i));
	            }
	        }
		} catch (Exception e) {
		}
	}

3、 部分機型適配

部分機型上文本顏色是完全隨通知欄顏色,在xml佈局中不論設顏色textcolor,或樣式style都無法改變按鈕的顏色,使用mRemoteViews.setTextColor(viewId, color)也無法改變顏色,這時候可以用SpannableString解決。

SpannableString str = new SpannableString(showText);
                ForegroundColorSpan span = new ForegroundColorSpan(Color.WHITE);  
                str.setSpan(span, 0, showText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                
                mRemoteViews.setTextViewText(key, str);

六、支持的控件

按其他參考文檔說法,TextView、Button、ImageView、ImageButton等基礎控件都是支持的,不過我測試發現ImageButton不支持,只要有該控件,則自定義通知欄無法展示,改爲ImageView即可。可能與前文所述的targetVersion有關,沒有做深入分析。

 

 七、動作響應PendingIntent

mRemoteViews.setOnClickPendingIntent(key,
                        getViewOnClickIntent(context, param.id, key));

PendingIntent包裹一個Intent,在條件觸發時纔會執行Intent動作。自定義通知欄按鈕點擊事件就是一個PendingIntent,示例如下:

private static PendingIntent getViewOnClickIntent(Context context, int paramId, int btnResId) {
        Intent intent = new Intent(ACTION_NOTIFY_BAR_BTN_CLICKED);
        intent.putExtra(PARAM_ID, paramId);
        intent.putExtra(BTN_CLICKED, btnResId);
        PendingIntent pendingIntent = 
                PendingIntent.getService(context, 
                        paramId + btnResId, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        return pendingIntent;
    }

這裏Intent的構造可以隨意,PendingIntent.getService、getActivity、getBroadcast皆可使用。第二個餐食requestCode和第四個參數flags可以起到更新通知欄的作用。

 

參考資料:

1、  http://blog.sina.com.cn/s/blog_80a855370101hqsq.html

2、  http://www.tuicool.com/articles/JZ7Bbu

3、  http://blog.csdn.net/asce1885/article/details/7802627

4、  http://blog.csdn.net/vipzjyno1/article/details/25248021

5、  http://www.androideng.com/?p=1069




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章