一、需求:个人主页顶部背景图,背景图上左上角有返回按钮。最开始做的返回按钮是白色的,但是考虑到背景色可能也是白色的,所以最好的做法是用两套返回按钮图,黄色和白色,根据背景色的颜色来设置返回按钮的颜色。
看图,看右上角的设置按钮颜色:
二、关于HSV颜色的简介(主要用到这玩意)。
HSV(Hue, Saturation, Value)也称六角锥体模型。
色调H
用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°,品红为300°;
饱和度S
饱和度S表示颜色接近光谱色的程度。一种颜色,可以看成是某种光谱色与白色混合的结果。其中光谱色所占的比例愈大,颜色接近光谱色的程度就愈高,颜色的饱和度也就愈高。饱和度高,颜色则深而艳。光谱色的白光成分为0,饱和度达到最高。通常取值范围为0%~100%,值越大,颜色越饱和。
明度V
明度表示颜色明亮的程度,对于光源色,明度值与发光体的光亮度有关;对于物体色,此值和物体的透射比或反射比有关。通常取值范围为0%(黑)到100%(白)。
RGB和CMY颜色模型都是面向硬件的,而HSV(Hue Saturation Value)颜色模型是面向用户的。
HSV模型的三维表示从RGB立方体演化而来。设想从RGB沿立方体对角线的白色顶点向黑色顶点观察,就可以看到立方体的六边形外形。六边形边界表示色彩,水平轴表示纯度,明度沿垂直轴测量。
三、如何实现
首先看工具类,其中我们只用到了HSV颜色,RGB的只是写的玩的,用不到
public class CaptureColorUtil {
private Context mContext;
private String url;
private int x;
private int y;
private int width;
private int height;
private int argb0;
private int argb1;
private int argb3;
private int argb2;
private int argb4;
private static CaptureColorUtil instance;
public static CaptureColorUtil getInstance(Context context, String url, int x, int y, int width, int height) {
if (instance == null) {
synchronized (CaptureColorUtil.class) {
if (instance == null) {
return new CaptureColorUtil(context, url, x, y, width, height);
}
}
}
return instance;
}
private CaptureColorUtil(Context context, String url, int x, int y, int width, int height) {
this.mContext = context;
this.url = url;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
getPixColor();
}
OnLoadListener onLoadListener;
public interface OnLoadListener {
void onLoadListener(float arg0, float arg1, float arg2);
}
void setLoadListener(OnLoadListener onLoadListener) {
this.onLoadListener = onLoadListener;
}
public void getPixColors(OnLoadListener onLoadListener) {
setLoadListener(onLoadListener);
}
public void getPixColor() {
Glide.with(mContext).asBitmap().load(url).into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(Bitmap resource, Transition<? super Bitmap> transition) {
int A0, R0, G0, B0, A1, R1, G1, B1, A2, R2, G2, B2, A3, R3, G3, B3, A4, R4, G4, B4;
float h0, s0, v0, h1, s1, v1, h2, s2, v2, h3, s3, v3, h4, s4, v4;
float[] hsv = new float[3];
int pixel0 = resource.getPixel(x, y);
Color.colorToHSV(pixel0, hsv);
h0 = hsv[0];
s0 = hsv[1];
v0 = hsv[2];
Log.e("hsvvvvv1:", h0 + "");
Log.e("hsvvvvv2:", s0 + "");
Log.e("hsvvvvv3:", v0 + "");
A0 = Color.alpha(pixel0);
R0 = Color.red(pixel0);
G0 = Color.green(pixel0);
B0 = Color.blue(pixel0);
argb0 = Color.argb(A0, R0, G0, B0);
int pixel1 = resource.getPixel(x + width, y);
Color.colorToHSV(pixel1, hsv);
h1 = hsv[0];
s1 = hsv[1];
v1 = hsv[2];
Log.e("hsvvvvv1:", h1 + "");
Log.e("hsvvvvv2:", s1 + "");
Log.e("hsvvvvv3:", v1 + "");
A1 = Color.alpha(pixel1);
R1 = Color.red(pixel1);
G1 = Color.green(pixel1);
B1 = Color.blue(pixel1);
argb1 = Color.argb(A1, R1, G1, B1);
int pixel2 = resource.getPixel(x, y + height);
Color.colorToHSV(pixel2, hsv);
h2 = hsv[0];
s2 = hsv[1];
v2 = hsv[2];
Log.e("hsvvvvv1:", h2 + "");
Log.e("hsvvvvv2:", s2 + "");
Log.e("hsvvvvv3:", v2 + "");
A2 = Color.alpha(pixel2);
R2 = Color.red(pixel2);
G2 = Color.green(pixel2);
B2 = Color.blue(pixel2);
argb2 = Color.argb(A2, R2, G2, B2);
int pixel3 = resource.getPixel(x + width, y + height);
Color.colorToHSV(pixel3, hsv);
h3 = hsv[0];
s3 = hsv[1];
v3 = hsv[2];
Log.e("hsvvvvv1:", h3+ "");
Log.e("hsvvvvv2:", s3 + "");
Log.e("hsvvvvv3:", v3 + "");
A3 = Color.alpha(pixel3);
R3 = Color.red(pixel3);
G3 = Color.green(pixel3);
B3 = Color.blue(pixel3);
argb3 = Color.argb(A3, R3, G3, B3);
int pixel4 = resource.getPixel(x + width / 2, y + height / 2);
Color.colorToHSV(pixel4, hsv);
h4 = hsv[0];
s4 = hsv[1];
v4 = hsv[2];
Log.e("hsvvvvv1:", h4+ "");
Log.e("hsvvvvv2:", s4 + "");
Log.e("hsvvvvv3:", v4 + "");
A4 = Color.alpha(pixel4);
R4 = Color.red(pixel4);
G4 = Color.green(pixel4);
B4 = Color.blue(pixel4);
argb4 = Color.argb(A4, R4, G4, B4);
float h = (h0 + h1 + h2 + h3 + h4) / 5;
float s = (s0 + s1 + s2 + s3 + s4) / 5;
float v = (v0 + v1 + v2 + v3 + v4) / 5;
if (onLoadListener != null) {
onLoadListener.onLoadListener(h, s, v);
}
Log.e("A0:", A0 + "");
Log.e("R0:", R0 + "");
Log.e("G0:", G0 + "");
Log.e("B0:", B0 + "");
Log.e("A1:", A1 + "");
Log.e("R1:", R1 + "");
Log.e("G1:", G1 + "");
Log.e("B1:", B1 + "");
Log.e("A2:", A2 + "");
Log.e("R2:", R2 + "");
Log.e("G2:", G2 + "");
Log.e("B2:", B2 + "");
Log.e("A3:", A3 + "");
Log.e("R3:", R3 + "");
Log.e("G3:", G3 + "");
Log.e("B3:", B3 + "");
Log.e("A4:", A4 + "");
Log.e("R4:", R4 + "");
Log.e("G4:", G4 + "");
Log.e("B4:", B4 + "");
}
});
}
}
然后是使用这个工具类:
CaptureColorUtil instance = CaptureColorUtil.getInstance(this, url, 30, 10, 40, 40);
if (TextUtils.isEmpty(url)) {
back.setImageResource(R.drawable.common_nav_btn_back_yellow);
} else {
instance.getPixColors(new CaptureColorUtil.OnLoadListener() {
@Override
public void onLoadListener(float arg0, float arg1, float arg2) {
LogUtil.e(TAG, "pixColor0: " + arg0);
LogUtil.e(TAG, "pixColor1 " + arg1);
LogUtil.e(TAG, "pixColor2 " + arg2);
/**
* 判断背景色为黄色,都用白色icon
H>26&&H<80
S>0.3
判断是否是亮色,亮色并且灰度趋向黑白,用黄色icon
S<0.3
V>0.8
其他,白色icon
*/
if (arg0 > 26 && arg0 < 80 && arg1 > 0.3f) {
back.setImageResource(R.drawable.common_nav_btn_back);
} else if (arg1 < 0.3f && arg2 > 0.8f) {
back.setImageResource(R.drawable.common_nav_btn_back_yellow);
} else {
back.setImageResource(R.drawable.common_nav_btn_back);
}
}
});
}
四、关于用法的解释和疑问
1.我们背景是可以改变的,返回键是黄色和白色两种。那么如果背景是黄色,并且不是灰色的,就直接上白色icon。 H>26&&H<80, S>0.3
如果背景亮度很高,并且灰度趋向于黑白色,就用黄色icon。 S<0.3 V>0.8。其他所有情况都用白色icon.
2.问题很明显了,我的这些判断条件都是我自己认为的,并没有严格的规则,也没有经过严格的测试,这些数据都是大致的,所以这每个取值的界限都存在误差。
3.取点,我只取了5个点来判断色值,实际上应该取这个范围的所有像素点,然后看哪个色值较多。
4.不知道能不能直接拿颜色的整数值或者其他更简单办法来判断背景是什么颜色,然后来判断应该用白色icon还是黄色icon?
5这个设置按钮颜色搞定了,接下来是不是应该动态改一改状态栏颜色了呢?当然不改,ios都不改,我干嘛改。。