说明:大部分内容都是参考别的文章,这里做整理是为了以后的编程有实用的模板,可以即需即用。
默认的通知栏样式:
private void sendDefaultNotification() {
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Intent intent = new Intent(this, TestActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification.Builder builder = new Notification
.Builder(getApplicationContext())
.setSmallIcon(R.mipmap.ic_launcher)// 一定要设置
.setTicker("状态栏标题")
.setContentTitle("内容标题")
.setContentText("内容")
.setDefaults(Notification.DEFAULT_ALL)
.setPriority(Notification.PRIORITY_MAX)
.setAutoCancel(true)
.setContentIntent(pendingIntent);
//8.0 以后需要加上channelId 才能正常显示
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String channelId = getApplicationContext().getPackageName();
String channelName = "默认通知";
notificationManager.createNotificationChannel(new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH));
// 一定要加上,不然不显示
builder.setChannelId(getApplicationContext().getPackageName());
}
notificationManager.notify(1, builder.build());
}
自定义的通知栏样式:
private void sendCustomNotification() {
final NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Intent intent = new Intent(this, TestActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Uri soundUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + getApplicationContext().getPackageName() + "/" + R.raw.ring);
// 如果音频文件已保存到本地,则采用下面代码
/*Uri soundUri;
String path = "xxx/xxx.mp"
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
soundUri = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".provider", new File(path));
} else {
soundUri = Uri.fromFile(new File(path));
}*/
mRemoteViews = new RemoteViews(getPackageName(), R.layout.notification_custom);
Notification.Builder builder = new Notification
.Builder(getApplicationContext())
.setSmallIcon(R.mipmap.zzjeohbs)// 一定要设置
.setContent(mRemoteViews)// 默认情况下通知高度为64dp(但是又有一些不止64,比如vivo)
//.setDefaults(Notification.DEFAULT_ALL)
.setSound(soundUri)
.setPriority(Notification.PRIORITY_MAX)
.setAutoCancel(true)
.setContentIntent(pendingIntent);
//8.0 以后需要加上channelId 才能正常显示
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String channelId = getApplicationContext().getPackageName();
String channelName = "默认通知";
NotificationChannel notificationChannel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH);
// For API 26+ you need to set the sound on the notification channel
AudioAttributes audioAttributes = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_NOTIFICATION)
.build();
notificationChannel.setSound(soundUri, audioAttributes);
notificationManager.createNotificationChannel(notificationChannel);
// 一定要加上,不然不显示
builder.setChannelId(getApplicationContext().getPackageName());
} else {
builder.setSound(soundUri);
//.setSound(soundUri, AudioManager.STREAM_MUSIC)
}
final Notification notification = builder.build();
// 适配oppo自定义通知栏无法显示问题
notification.flags = Notification.FLAG_AUTO_CANCEL | Notification.FLAG_ONGOING_EVENT;
// api 24 builder.setCustomBigContentView(getBigRemoteViews());
// notification.bigContentView = getBigRemoteViews(); // api 16 bigContentView 的最大高度是256dp
Glide.with(this)
.load("https://imgs.gmilesquan.com/img/home/titlebar_tab.png")
.asBitmap()
.into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
mRemoteViews.setImageViewBitmap(R.id.iv_title, resource);
mRemoteViews.setTextViewText(R.id.tv_content, "推送内容");
// TODO: 2019/8/12 通知之前要完成数据装载
notificationManager.notify(1, notification);
}
});
}
private RemoteViews getBigRemoteViews() {
RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.notification_big_custom);
remoteViews.setTextViewText(R.id.tv_content, "推送内容");
return remoteViews;
}
notification_custom.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="70dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_title"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
tools:src="@mipmap/ic_launcher" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginTop="5dp"
android:layout_toRightOf="@id/iv_title"
android:orientation="vertical">
<TextView
android:id="@+id/tv_title"
style="@style/NotificationTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
android:text="测试title" />
<TextView
android:id="@+id/tv_content"
style="@style/NotificationInfo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:ellipsize="end"
android:maxLines="1"
android:text="测试" />
</LinearLayout>
</RelativeLayout>
notification_big_custom.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="256dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_title"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:src="@mipmap/ic_launcher" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/iv_title"
android:orientation="vertical">
<TextView
android:id="@+id/tv_title"
style="@style/NotificationTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="测试title" />
<TextView
android:id="@+id/tv_content"
style="@style/NotificationInfo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="测试" />
</LinearLayout>
</RelativeLayout>
自定义通知栏时,因为各手机系统通知栏的背景主题明暗不同,所以建议内容文本颜色采用系统提供样式,api_21前后不同,所以要在values-v21文件中做适配:
1、默认 values
<!-- Android 自定义Notification字体颜色适配 -->
<style name="NotificationInfo" parent="android:TextAppearance.StatusBar.EventContent" />
<style name="NotificationTitle" parent="android:TextAppearance.StatusBar.EventContent.Title" />
2、values-v21
<!-- Android 自定义Notification字体颜色适配 -->
<style name="NotificationInfo" parent="android:TextAppearance.Material.Notification.Info" />
<style name="NotificationTitle" parent="android:TextAppearance.Material.Notification.Title" />
上面的内容文本颜色适配方案,在某些手机系统上还是生效不了,所以在网上找到了下面这个方案,通过分析系统通知栏主题色系是明还是暗,来设置内容文本颜色明暗:
private boolean isDarkNotificationTheme(Context context) {
return !isSimilarColor(Color.BLACK, getNotificationColor(context));
}
private int getNotificationColor(Context context) {
Notification.Builder builder = new Notification.Builder(context);
Notification notification = builder.build();
int layoutId = notification.contentView.getLayoutId();
ViewGroup viewGroup = (ViewGroup) LayoutInflater.from(context).inflate(layoutId, null, false);
if (viewGroup.findViewById(android.R.id.title) != null) {
return ((TextView) viewGroup.findViewById(android.R.id.title)).getCurrentTextColor();
}
return findColor(viewGroup);
}
private boolean isSimilarColor(int baseColor, int color) {
int simpleBaseColor = baseColor | 0xff000000;
int simpleColor = color | 0xff000000;
int baseRed = Color.red(simpleBaseColor) - Color.red(simpleColor);
int baseGreen = Color.green(simpleBaseColor) - Color.green(simpleColor);
int baseBlue = Color.blue(simpleBaseColor) - Color.blue(simpleColor);
double value = Math.sqrt(baseRed * baseRed + baseGreen * baseGreen + baseBlue * baseBlue);
if (value < 180.0) {
return true;
}
return false;
}
private int findColor(ViewGroup viewGroupSource) {
int color = Color.TRANSPARENT;
LinkedList<ViewGroup> viewGroups = new LinkedList<>();
viewGroups.add(viewGroupSource);
while (viewGroups.size() > 0) {
ViewGroup viewGroup1 = viewGroups.getFirst();
for (int i = 0; i < viewGroup1.getChildCount(); i++) {
if (viewGroup1.getChildAt(i) instanceof ViewGroup) {
viewGroups.add((ViewGroup) viewGroup1.getChildAt(i));
} else if (viewGroup1.getChildAt(i) instanceof TextView) {
if (((TextView) viewGroup1.getChildAt(i)).getCurrentTextColor() != -1) {
color = ((TextView) viewGroup1.getChildAt(i)).getCurrentTextColor();
}
}
}
viewGroups.remove(viewGroup1);
}
return color;
}
这个适配方案在某些国产手机系统上运行分析时,会奔溃,呵呵:
try {
if (isDarkNotificationTheme(context)) {
remoteViews.setTextColor(R.id.tv_title, context.getResources().getColor(R.color.custom_notification_title_color));
remoteViews.setTextColor(R.id.tv_content, context.getResources().getColor(R.color.custom_notification_content_color));
}
} catch (Exception e) {
e.printStackTrace();
}
private int getNotificationColor(Context context) {
Notification.Builder builder = new Notification.Builder(context);
Notification notification = builder.build();
RemoteViews contentView = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
contentView = builder.createContentView();
} else {
// As of N, this field may be null.
contentView = notification.contentView;
}
int layoutId = contentView.getLayoutId();
ViewGroup viewGroup = (ViewGroup) LayoutInflater.from(context).inflate(layoutId, null, false);
if (viewGroup.findViewById(android.R.id.title) != null) {
return ((TextView) viewGroup.findViewById(android.R.id.title)).getCurrentTextColor();
}
return findColor(viewGroup);
}
还有一点,我们有时只想设置不带icon的文本通知,但是在某些国产手机系统上,还是会在左上角展示一个小icon,甚至有些会在左边展示一个大icon。。。
参考文章:
1、https://blog.csdn.net/u010005281/article/details/78708172
2、https://blog.csdn.net/cloudzyy/article/details/83151090