目前android碎片化严重,不少厂商会针对android系统底层进行改造,通知栏也不例外,相似小米手机或者华为的一些手机,通知栏就不是原生android的,有些通知栏的背景是黑色,有些通知栏的背景是白色,因此在应用中须要自定义通知栏的时候,很难去适配机器自身通知栏的样式,目前不少应用在实现自定义通知栏的时候,为了适配全部机型,一般会在自定义通知栏的时候加一层背景,例以下面的360:java
适配的方式大概有两种,一种简单粗暴:为自定义通知设置固定的背景(上图中的360卫士就这么干的),好比黑色。那么内容天然就是白色或近似白色。这样,在全部的手机上都能正常显示,不会出如今黑色背景通知栏上显示良好,到了白色背景通知栏上就几乎啥也看不见。使用这种方案的应用太多了。我我的很不推崇这种方式,这样会使得自定义通知在将近一半的手机上显示得很突兀,和系统的通知栏不够沉浸,影响总体美观。另外一种方案就稍微合理一些:经过读取系统的通知栏样式文件,获取到title和content的颜色,进而将这个颜色设置到自定义通知上。读取通知栏样式文件自己有兼容性问题,不一样Android版本的样式文件有变,具体可参考这篇博客 通知栏设置系统字体颜色 ,这种方式也不是在全部手机上生效,实际测试发现,仍是有小部分机型无法读取或是读取到的是错误的。拿到title和content的颜色后,还能够经过算法(后面细说)判断这个颜色是近似白色仍是近似黑色,进而能判断出通知栏的背景是近似黑色仍是近似白色,这样就能根据不一样的通知栏背景加载不一样的自定义通知布局。进而作到良好的适配。android
/** * 通知栏的帮助类,提供查询手机是否禁止通知栏,判断通知栏背景颜色 * Created by dengqu on 2016/12/12. */ public class NotificationsUtils { private final static String TAG = NotificationsUtils.class.getSimpleName(); private static final String CHECK_OP_NO_THROW = "checkOpNoThrow"; private static final String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION"; private static final double COLOR_THRESHOLD = 180.0; private static int titleColor; /** * 判断应用通知栏是否开启权限 * * @param context * @return */ public static boolean isNotificationEnabled(Context context) { try { if (AndroidConfig.getAndroidVersion() >= Build.VERSION_CODES.KITKAT) { AppOpsManager mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); ApplicationInfo appInfo = context.getApplicationInfo(); String pkg = context.getApplicationContext().getPackageName(); int uid = appInfo.uid; Class appOpsClass = null; appOpsClass = Class.forName(AppOpsManager.class.getName()); Method checkOpNoThrowMethod = appOpsClass.getMethod(CHECK_OP_NO_THROW, Integer.TYPE, Integer.TYPE, String.class); Field opPostNotificationValue = appOpsClass.getDeclaredField(OP_POST_NOTIFICATION); int value = (int) opPostNotificationValue.get(Integer.class); return ((int) checkOpNoThrowMethod.invoke(mAppOps, value, uid, pkg) == AppOpsManager.MODE_ALLOWED); } } catch (Exception e) { XLLog.e(TAG, e); } return true; } /** * 判断通知栏背景颜色,如今手机通知栏大部分不是白色就是黑色背景 * * @param context * @return */ public static boolean isDarkNotiFicationBar(Context context) { return !isColorSimilar(Color.BLACK, getNotificationColor(context)); } private static int getNotificationColor(Context context) { if (context instanceof AppCompatActivity) { return getNotificationColorCompat(context); } else { return getNotificationColorInternal(context); } } private static boolean isColorSimilar(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 < COLOR_THRESHOLD) { return true; } return false; } private static int getNotificationColorInternal(Context context) { final String DUMMY_TITLE = "DUMMY_TITLE"; NotificationCompat.Builder builder = new NotificationCompat.Builder(context); builder.setContentText(DUMMY_TITLE); Notification notification = builder.build(); ViewGroup notificationRoot = (ViewGroup) notification.contentView.apply(context, new FrameLayout(context)); final TextView titleView = (TextView) notificationRoot.findViewById(android.R.id.title); if (titleView == null) { iteratoryView(notificationRoot, new Filter() { @Override public void filter(View view) { if (view instanceof TextView) { TextView textView = (TextView) view; if (DUMMY_TITLE.equals(textView.getText().toString())) { titleColor = textView.getCurrentTextColor(); } } } }); return titleColor; } else { return titleView.getCurrentTextColor(); } } private static int getNotificationColorCompat(Context context) { NotificationCompat.Builder builder = new NotificationCompat.Builder(context); Notification notification = builder.build(); int layoutId = notification.contentView.getLayoutId(); ViewGroup notificationRoot = (ViewGroup) LayoutInflater.from(context).inflate(layoutId, null); final TextView titleView = (TextView) notificationRoot.findViewById(android.R.id.title); if (titleView == null) { final List<TextView> textViews = new ArrayList<>(); iteratoryView(notificationRoot, new Filter() { @Override public void filter(View view) { textViews.add((TextView) view); } }); float minTextSize = Integer.MIN_VALUE; int index = 0; for (int i = 0, j = textViews.size(); i < j; i++) { float currentSize = textViews.get(i).getTextSize(); if (currentSize > minTextSize) { minTextSize = currentSize; index = i; } } return textViews.get(index).getCurrentTextColor(); } else { return titleView.getCurrentTextColor(); } } private static void iteratoryView(View view, Filter filter) { if (view == null || filter == null) { return; } filter.filter(view); if (view instanceof ViewGroup) { ViewGroup container = (ViewGroup) view; for (int i = 0, j = container.getChildCount(); i < j; i++) { View child = container.getChildAt(i); iteratoryView(child, filter); } } } private interface Filter { void filter(View view); } }