Android 自定义通知栏实现资料总结

时间:2022-01-03 19:35:10

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 自定义通知栏实现资料总结

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