說明:大部分內容都是參考別的文章,這裏做整理是爲了以後的編程有實用的模板,可以即需即用。
默認的通知欄樣式:
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