NotificationCompat 中的 BigTextStyle 导致图形错误
BigTextStyle in NotificationCompat cause graphical bug
我有一个通知,支持私有和 public 版本。私有版本显示为 bigTextStyle。两个版本的图标都生成为 LayerDrawable,然后将其转换为位图。这适用于所有设备。除了在地狱中锻造的华为 Ascent Mate 7。 (Android 4.4.2, EMUI 3.0)
在未展开的版本中,它看起来应该如此。圆圈,适合图标。
但在放大版中,它看起来就像是从图标的缩放版中剪下来的。
我做的图标如下:
Drawable background = ContextCompat.getDrawable(this, R.drawable.shape_notification_circle);
if (background != null) {
PorterDuffColorFilter filter = new PorterDuffColorFilter(ThemeManager.getInstance().getTheme()
.getColorMainDark(), PorterDuff.Mode.SRC_ATOP);
background.setColorFilter(filter);
}
Drawable[] layers = {background, ContextCompat.getDrawable(this, icon)};
//icon is an int, containing the resource id
LayerDrawable layerDrawable = new LayerDrawable(layers);
int padding = dpToPx(24);
layerDrawable.setLayerInset(1, padding, padding, padding, padding);
Bitmap iconBitmap = drawableToBitmap(layerDrawable);
方法 drawableToBitmap:
public static Bitmap drawableToBitmap(Drawable drawable) {
Bitmap bitmap;
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if (bitmapDrawable.getBitmap() != null) {
return bitmapDrawable.getBitmap();
}
}
if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of
// 1x1 pixel
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config
.ARGB_8888);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
shape_notification_circle
的布局
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#666666"/>
<size
android:width="48dp"
android:height="48dp"/>
</shape>
可绘制的图标:
<?xml version="1.0" encoding="UTF-8"?>
<vector android:height="48dp"
android:viewportHeight="1000.0"
android:viewportWidth="1000.0"
android:width="48dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<path
android:fillColor="#FFFFFF"
android:pathData="M500,609.8l-75.20001,-72.79999l-299.69998,252.79999l749.80005,0l-299.7,-252.79999z"/>
<path
android:fillColor="#FFFFFF"
android:pathData="M122.6,210.2l377.4,365l377.40002,-365z"/>
<path
android:fillColor="#FFFFFF"
android:pathData="M406.3,519.7l-300.9,-292.2l0,546.3z"/>
<path
android:fillColor="#FFFFFF"
android:pathData="M894.6,773.8l0,-546.3l-300.89996,292.2z"/>
</vector>
最后,创建通知。 (notificationBuilder和notificationBuilderPublic以前是不同的,现在一样了,除了bigTextStyle不同)
// @formatter:off
NotificationCompat.Builder notificationBuilderPublic = new NotificationCompat.Builder(this)
.setLargeIcon(iconBitmap)
.setSmallIcon(R.drawable.ic_notification_launcher)
.setColor(ThemeManager.getInstance().getTheme().getColorAccent())
.setDefaults(Notification.DEFAULT_ALL)
.setContentTitle(getString(R.string.app_name))
.setContentText(title)
.setAutoCancel(true)
.setContentIntent(pendingIntent)
.setCategory(category)
.setPriority(priority)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
;
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setLargeIcon(iconBitmap)
.setSmallIcon(R.drawable.ic_notification_launcher)
.setColor(ThemeManager.getInstance().getTheme().getColorAccent())
.setDefaults(Notification.DEFAULT_ALL)
.setContentTitle(getString(R.string.app_name))
.setContentText(title)
.setAutoCancel(true)
.setContentIntent(pendingIntent)
.setCategory(category)
.setPriority(priority)
.setVisibility(visibility)
;
// @formatter:on
notificationBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(text)
.setBigContentTitle(getString(R.string.app_name)).setSummaryText(extraSummary));
notificationBuilder.setPublicVersion(notificationBuilderPublic.build());
notificationManager.notify(pushId + "|" + ownermoduleid + "|" + fid, type.getId(), notificationBuilder.build());
我做错了什么?
编辑:添加布局和图标XML
最后我找到了...好吧,我不会称之为解决方案...一种变通方法。看起来,在 LayerDrawable 的图层上设置 insets 会导致图像变大。如果某些设备太大,它们似乎会裁剪图像而不是适合它们。
这导致我在将 iconBitmap 设置为 LargeIcon 之前调整它的大小。
Bitmap iconBitmap = scaleDown(drawableToBitmap(layerDrawable), dpToPx(48), true);
和缩放函数
public Bitmap scaleDown(Bitmap source, int size, boolean filter) {
return Bitmap.createScaledBitmap(source, size, size, filter);
}
这仍然不能完美无缺。展开通知时,图像稍微小了一点,但这对我来说没问题。还是比裁剪的好。
我还是不知道,为什么只有在展开视图时才会出现这种情况。也许华为的人实现了不同于普通样式的 BigTextStyle。或者也许这只是一些黑魔法...
如果有人提出更好的解决方案,我会接受。
我有一个通知,支持私有和 public 版本。私有版本显示为 bigTextStyle。两个版本的图标都生成为 LayerDrawable,然后将其转换为位图。这适用于所有设备。除了在地狱中锻造的华为 Ascent Mate 7。 (Android 4.4.2, EMUI 3.0)
在未展开的版本中,它看起来应该如此。圆圈,适合图标。
但在放大版中,它看起来就像是从图标的缩放版中剪下来的。
我做的图标如下:
Drawable background = ContextCompat.getDrawable(this, R.drawable.shape_notification_circle);
if (background != null) {
PorterDuffColorFilter filter = new PorterDuffColorFilter(ThemeManager.getInstance().getTheme()
.getColorMainDark(), PorterDuff.Mode.SRC_ATOP);
background.setColorFilter(filter);
}
Drawable[] layers = {background, ContextCompat.getDrawable(this, icon)};
//icon is an int, containing the resource id
LayerDrawable layerDrawable = new LayerDrawable(layers);
int padding = dpToPx(24);
layerDrawable.setLayerInset(1, padding, padding, padding, padding);
Bitmap iconBitmap = drawableToBitmap(layerDrawable);
方法 drawableToBitmap:
public static Bitmap drawableToBitmap(Drawable drawable) {
Bitmap bitmap;
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if (bitmapDrawable.getBitmap() != null) {
return bitmapDrawable.getBitmap();
}
}
if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of
// 1x1 pixel
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config
.ARGB_8888);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
shape_notification_circle
的布局<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#666666"/>
<size
android:width="48dp"
android:height="48dp"/>
</shape>
可绘制的图标:
<?xml version="1.0" encoding="UTF-8"?>
<vector android:height="48dp"
android:viewportHeight="1000.0"
android:viewportWidth="1000.0"
android:width="48dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<path
android:fillColor="#FFFFFF"
android:pathData="M500,609.8l-75.20001,-72.79999l-299.69998,252.79999l749.80005,0l-299.7,-252.79999z"/>
<path
android:fillColor="#FFFFFF"
android:pathData="M122.6,210.2l377.4,365l377.40002,-365z"/>
<path
android:fillColor="#FFFFFF"
android:pathData="M406.3,519.7l-300.9,-292.2l0,546.3z"/>
<path
android:fillColor="#FFFFFF"
android:pathData="M894.6,773.8l0,-546.3l-300.89996,292.2z"/>
</vector>
最后,创建通知。 (notificationBuilder和notificationBuilderPublic以前是不同的,现在一样了,除了bigTextStyle不同)
// @formatter:off
NotificationCompat.Builder notificationBuilderPublic = new NotificationCompat.Builder(this)
.setLargeIcon(iconBitmap)
.setSmallIcon(R.drawable.ic_notification_launcher)
.setColor(ThemeManager.getInstance().getTheme().getColorAccent())
.setDefaults(Notification.DEFAULT_ALL)
.setContentTitle(getString(R.string.app_name))
.setContentText(title)
.setAutoCancel(true)
.setContentIntent(pendingIntent)
.setCategory(category)
.setPriority(priority)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
;
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setLargeIcon(iconBitmap)
.setSmallIcon(R.drawable.ic_notification_launcher)
.setColor(ThemeManager.getInstance().getTheme().getColorAccent())
.setDefaults(Notification.DEFAULT_ALL)
.setContentTitle(getString(R.string.app_name))
.setContentText(title)
.setAutoCancel(true)
.setContentIntent(pendingIntent)
.setCategory(category)
.setPriority(priority)
.setVisibility(visibility)
;
// @formatter:on
notificationBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(text)
.setBigContentTitle(getString(R.string.app_name)).setSummaryText(extraSummary));
notificationBuilder.setPublicVersion(notificationBuilderPublic.build());
notificationManager.notify(pushId + "|" + ownermoduleid + "|" + fid, type.getId(), notificationBuilder.build());
我做错了什么?
编辑:添加布局和图标XML
最后我找到了...好吧,我不会称之为解决方案...一种变通方法。看起来,在 LayerDrawable 的图层上设置 insets 会导致图像变大。如果某些设备太大,它们似乎会裁剪图像而不是适合它们。
这导致我在将 iconBitmap 设置为 LargeIcon 之前调整它的大小。
Bitmap iconBitmap = scaleDown(drawableToBitmap(layerDrawable), dpToPx(48), true);
和缩放函数
public Bitmap scaleDown(Bitmap source, int size, boolean filter) {
return Bitmap.createScaledBitmap(source, size, size, filter);
}
这仍然不能完美无缺。展开通知时,图像稍微小了一点,但这对我来说没问题。还是比裁剪的好。
我还是不知道,为什么只有在展开视图时才会出现这种情况。也许华为的人实现了不同于普通样式的 BigTextStyle。或者也许这只是一些黑魔法...
如果有人提出更好的解决方案,我会接受。