android 通知栏播放器,Android 播放器通知栏样式适配

一、获取通知栏主题颜色

由于调用系统的属性,获取颜色在某些手机上是不兼容的。因此采用先创建一个系统通知栏对象,然后迭代其中的 View 获取对应的颜色。代码如下:

import android.app.Notification;

import android.content.Context;

import android.support.v4.app.NotificationCompat;

import android.support.v7.app.AppCompatActivity;

import android.util.Log;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.FrameLayout;

import android.widget.TextView;

import java.util.ArrayList;

import java.util.List;

/**

* Created by iOnesmile on 06/07/2017.

*/

public class NotificationColor {

private static final String NOTIFICATION_TITLE = "notification_title";

public static final int INVALID_COLOR = -1; // 无效颜色

private static int notificationTitleColor = INVALID_COLOR; // 获取到的颜色缓存

/**

* 获取系统通知栏主标题颜色,根据Activity继承自AppCompatActivity或FragmentActivity采取不同策略。

*

*@param context 上下文环境

*@return 系统主标题颜色

*/

public static int getNotificationColor(Context context) {

try {

if (notificationTitleColor == INVALID_COLOR) {

if (context instanceof AppCompatActivity) {

notificationTitleColor = getNotificationColorCompat(context);

} else {

notificationTitleColor = getNotificationColorInternal(context);

}

}

} catch (Exception ignored) {

}

return notificationTitleColor;

}

/**

* 通过一个空的Notification拿到Notification.contentView,通过{@link RemoteViews#apply(Context, ViewGroup)}方法返回通知栏消息根布局实例。

*

*@param context 上下文

*@return 系统主标题颜色

*/

private static int getNotificationColorInternal(Context context) {

NotificationCompat.Builder builder = new NotificationCompat.Builder(context);

builder.setContentTitle(NOTIFICATION_TITLE);

Notification notification = builder.build();

try {

ViewGroup root = (ViewGroup) notification.contentView.apply(context, new FrameLayout(context));

TextView titleView = (TextView) root.findViewById(android.R.id.title);

if (null == titleView) {

iteratorView(root, new Filter() {

@Override

public void filter(View view) {

if (view instanceof TextView) {

TextView textView = (TextView) view;

if (NOTIFICATION_TITLE.equals(textView.getText().toString())) {

notificationTitleColor = textView.getCurrentTextColor();

}

}

}

});

return notificationTitleColor;

} else {

return titleView.getCurrentTextColor();

}

} catch (Exception e) {

Log.e("NotificationColor", "", e);

return getNotificationColorCompat(context);

}

}

/**

* 使用getNotificationColorInternal()方法,Activity不能继承自AppCompatActivity(实测5.0以下机型可以,5.0及以上机型不行),

* 大致的原因是默认通知布局文件中的ImageView(largeIcon和smallIcon)被替换成了AppCompatImageView,

* 而在5.0及以上系统中,AppCompatImageView的setBackgroundResource(int)未被标记为RemotableViewMethod,导致apply时抛异常。

*

*@param context 上下文

*@return 系统主标题颜色

*/

private static int getNotificationColorCompat(Context context) {

try {

NotificationCompat.Builder builder = new NotificationCompat.Builder(context);

Notification notification = builder.build();

int layoutId = notification.contentView.getLayoutId();

ViewGroup root = (ViewGroup) LayoutInflater.from(context).inflate(layoutId, null);

TextView titleView = (TextView) root.findViewById(android.R.id.title);

if (null == titleView) {

return getTitleColorIteratorCompat(root);

} else {

return titleView.getCurrentTextColor();

}

} catch (Exception e) {

}

return INVALID_COLOR;

}

private static void iteratorView(View view, Filter filter) {

if (view == null || filter == null) {

return;

}

filter.filter(view);

if (view instanceof ViewGroup) {

ViewGroup viewGroup = (ViewGroup) view;

for (int i = 0; i < viewGroup.getChildCount(); i++) {

View child = viewGroup.getChildAt(i);

iteratorView(child, filter);

}

}

}

private static int getTitleColorIteratorCompat(View view) {

if (view == null) {

return INVALID_COLOR;

}

List textViews = getAllTextViews(view);

int maxTextSizeIndex = findMaxTextSizeIndex(textViews);

if (maxTextSizeIndex != Integer.MIN_VALUE) {

return textViews.get(maxTextSizeIndex).getCurrentTextColor();

}

return INVALID_COLOR;

}

private static int findMaxTextSizeIndex(List textViews) {

float max = Integer.MIN_VALUE;

int maxIndex = Integer.MIN_VALUE;

int index = 0;

for (TextView textView : textViews) {

if (max < textView.getTextSize()) {

// 找到字号最大的字体,默认把它设置为主标题字号大小

max = textView.getTextSize();

maxIndex = index;

}

index++;

}

return maxIndex;

}

/**

* 实现遍历View树中的TextView,返回包含TextView的集合。

*

*@param root 根节点

*@return 包含TextView的集合

*/

private static List getAllTextViews(View root) {

final List textViews = new ArrayList<>();

iteratorView(root, new Filter() {

@Override

public void filter(View view) {

if (view instanceof TextView) {

textViews.add((TextView) view);

}

}

});

return textViews;

}

private interface Filter {

void filter(View view);

}

}

二、渲染播放图标

播放器图标的渲染,采用 v4 包中的 tint 方法,代码如下:

public static Bitmap getBitmapByIdAndRender(Context context, int drawableResId, int renderColor) {

Drawable drawable = getDrawable(context, drawableResId);

drawable = tintDrawable(drawable, ColorStateList.valueOf(renderColor));

return drawableToBitmap(drawable);

}

public static Drawable getDrawable(Context context, int imageRes) {

Drawable drawable = context.getResources().getDrawable(imageRes);

drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());

return drawable;

}

public static Drawable tintDrawable(Drawable drawable, ColorStateList colors) {

final Drawable wrappedDrawable = DrawableCompat.wrap(drawable);

DrawableCompat.setTintList(wrappedDrawable, colors);

return wrappedDrawable;

}

在设置副标题的颜色时,我采用了给主标题设置一个透明度的方式来达到,通过 HSV 模型把颜色和透明度合成一个新的色值:

/**

* 把RGB + Alpha合成为一个新的RGB

*@param alpha

*@param color

*@return

*/

public static int getCompoundColor(int alpha, int color) {

float[] hsv = new float[]{0, 0, 1};

Color.colorToHSV(color, hsv);

hsv[2] = (alpha + 0.0f) / 0xFF;

color = Color.HSVToColor(hsv);

return color;

}

三、参考链接

Android自定义通知样式适配 http://www.jianshu.com/p/426d85f34561

Android通知栏介绍与适配总结 http://iluhcm.com/2017/03/12/experience-of-adapting-to-android-notifications/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值