App 黑白化实现扩展,一键护眼模式,给 App,安卓事件分发机制面试
Paint paint = new Paint();ColorMatrix cm = new ColorMatrix();// 关键起作用的代码,Saturation,翻译成中文就是饱和度的意思。// 官方文档说明:A value of 0 maps the color to gray-scale. 1 is identity.// 原来如此,666cm.setSaturation(0f);paint.setColorFilter(new ColorMatrixColorFilter(cm));view.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
没了解过的可以看这两篇复习下:
App 黑白化实现探索2, 发现了一种更方便的方案,我被锤了!
2 拆招
我们的操作对象是 ColorMatrix,它具体是个什么东东官方文档最清楚了,把文档请出来:
4x5 matrix for transforming the color and alpha components of a Bitmap. The matrix can be passed as single array, and is treated as follows:[ a, b, c, d, e,f, g, h, i, j,k, l, m, n, o,p, q, r, s, t ]When applied to a color [R, G, B, A], the resulting color is computed as:R’ = aR + bG + cB + dA + e;G’ = fR + gG + hB + iA + j;B’ = kR + lG + mB + nA + o;A’ = pR + qG + rB + sA + t;
「人」如其名,它是个 4x5 的矩阵,通过矩阵乘法和加法实现了颜色的转换,没看明白?这样能明白了吧:
那设置饱和度是如何影响颜色的呢?来看看 ColorMatrix.setSaturation 的具体实现
/**
Create a new colormatrix initialized to identity (as if reset() had
been called)./public ColorMatrix() {reset();}// 原始矩阵长这样/*
Set this colormatrix to identity:
[ 1 0 0 0 0 - red vector
0 1 0 0 0 - green vector
0 0 1 0 0 - blue vector
0 0 0 1 0 ] - alpha vector*/public void reset() {final float[] a = mArray;
for (int i = 19; i > 0; --i) {a[i] = 0;}a[0] = a[6] = a[12] = a[18] = 1;}/**
Set the matrix to affect the saturation of colors.
@param sat A value of 0 maps the color to gray-scale. 1 is identity.*/public void setSaturation(float sat) {reset();float[] m = mArray;final float invSat = 1 - sat;final float R = 0.213f * invSat;final float G = 0.715f * invSat;final float B = 0.072f * invSat;m[0] = R + sat; m[1] = G; m[2] = B;m[5] = R; m[6] = G + sat; m[7] = B;m[10] = R; m[11] = G; m[12] = B + sat;}
当我们设置饱和度 sat 为 0 时,上面矩阵里的 a, f, k 都变成了 0.213f,b, g, l 都变成了 0.715f,c, h, m 都变成了 0.072f,代入计算公式发现 R, G, B 取值变成一样了,这不就变成黑白色了吗!
3 亮招
通过前面的分析已经了清楚设置饱和度最终是通过修改矩阵来实现黑白色效果的,那我们直接修改矩阵呢?**比如护眼模式,不就是去蓝光吗!**上代码:
Window window = activity.getWindow();if (window == null) {return;}View view = window.getDecorView();Paint paint = new Paint();// 我们把蓝色减弱为原来的 0.7ColorMatrix cm = new ColorMatrix(new float[]{1, 0, 0, 0, 0,0, 1, 0, 0, 0,0, 0, 0.7f, 0, 0,0, 0, 0, 1, 0});paint.setColorFilter(new Co
lorMatrixColorFilter(cm));view.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
哟,真是神奇。
4 连招
如果前面的分析你都看懂了,你可能意识到这个 ColorMatrix 玩法还有很多,比如夜间模式,可能就是反色+降低亮度,反色代码如下:
Window window = activity.getWindow();if (window == null) {return;}View view = window.getDecorView();view.addOnLayoutChangeListener(this);if (view instanceof ViewGroup) {takeOffColor((ViewGroup) view);}Paint paint = new Paint();ColorMatrix cm = new ColorMatrix(new float[]{-1, 0, 0, 0, 255,0, -1, 0, 0, 255,0, 0, -1, 0, 255,0, 0, 0, 1, 0});paint.setColorFilter(new ColorMatrixColorFilter(cm));view.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
**但是有一个很明显的问题,因为我们是对 Activity 的 DecorView 做了颜色转换,ImageView 是它的 Child,所以图片也被反色了,在购物的场景下我想买黄色的衣服,结果收到货确实蓝色的,闹呢?那我们能不能单独给 ImageView 设置一个反向的矩阵让图片恢复原来的颜色呢?**直接上逆矩阵:
// 遍历查找 ImageView,对其设置逆矩阵 int childCount = parent.getChildCount();for (int i = 0; i < childCount; i++) {final View childView = parent.getChildAt(i);if (childView instanceof ViewGroup) {takeOffColor((ViewGroup) childView);
评论