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的参数进行设置。

三、 通知栏背景色问题

Android 自定义通知栏实现资料总结_第1张图片

在应用上集成自定义通知栏后,发现不管怎么设置布局背景色为透明,都无法和系统风格保持一致。最终定位发现是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




你可能感兴趣的:(android,自定义通知栏)