美文网首页Android进阶之路Android开发Android开发经验谈
别给APP造轮子了,来穿漂亮的裙子吧

别给APP造轮子了,来穿漂亮的裙子吧

作者: Android进阶小麦 | 来源:发表于2020-09-17 21:23 被阅读0次

一、看招

之前在鸿洋的公众号看到App黑白化方案的探索,那叫一个妙,我们先回顾下当时的招式

Window window = activity.getWindow();                
if (window == null) {                                
    return;                                          
}                                                    
View view = window.getDecorView();                   
Paint paint = new Paint();                           
ColorMatrix cm = new ColorMatrix(); 
// 关键起作用的代码,Saturation,翻译成中文就是饱和度的意思。
// 官方文档说明:A value of 0 maps the color to gray-scale. 1 is identity.
// 原来如此,666
cm.setSaturation(0f);                                
paint.setColorFilter(new ColorMatrixColorFilter(cm));
view.setLayerType(View.LAYER_TYPE_HARDWARE, paint);  
复制代码

二、拆招

我们的操作对象是 ColorMatrix,它具体是个什么东东官方文档最清楚了,把文档请出来:

「人」如其名,它是个 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.213fb, g, l都变成了0.715fc, h, m都变成了0.072f,代入计算公式发现R, G, B取值变成一样了,这不就变成黑白色了吗!

三、亮招

通过前面的分析已经了清楚设置饱和度最终是通过修改矩阵来实现黑白色效果的,那我们直接修改矩阵呢?比如护眼模式,不就是去蓝光吗!上代码:

Window window = activity.getWindow();
if (window == null) {
    return;
}
View view = window.getDecorView();
Paint paint = new Paint();
// 我们把蓝色减弱为原来的0.7
ColorMatrix 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 ColorMatrixColorFilter(cm));
view.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
复制代码

哟,真是神奇。

四、连招

如果前面的分析你都看懂了,你可能意识到这个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);
复制代码

但是有一个很明显的问题,因为我们是对ActivityDecorView做了颜色转换,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);
    } else if (childView instanceof ImageView) {
        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));
        childView.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
    }
}
复制代码

完美!!!

五、罩门

所谓罩门,就是功夫练不到的地方。前面看起来招招毙命,其实也有需要注意的地方,颜色转换算法是通过ColorMatrix完成了,但我们还借用了setLayerType将矩阵传递给底层的。

支持的ViewType

通过源码我们发现,三种Type中只有LAYER_TYPE_HARDWARELAYER_TYPE_SOFTWARE支持颜色转换:

public void setLayerType(int layerType, Paint paint) {
    if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) {
        throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, "
                + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE");
    }
    if (layerType == mLayerType) {
        // 1\. LAYER_TYPE_NONE 不支持paint参数
        if (layerType != LAYER_TYPE_NONE && paint != mLayerPaint) {
            mLayerPaint = paint == null ? new Paint() : paint;
            invalidateParentCaches();
            invalidate(true);
        }
        return;
    }
    // Destroy any previous software drawing cache if needed
    switch (mLayerType) {
        case LAYER_TYPE_HARDWARE:
            destroyLayer(false);
            // fall through - non-accelerated views may use software layer mechanism instead
        case LAYER_TYPE_SOFTWARE:
            destroyDrawingCache();
            break;
        default:
            break;
    }
    mLayerType = layerType;
    // 2\. LAYER_TYPE_NONE 不支持paint参数
    final boolean layerDisabled = mLayerType == LAYER_TYPE_NONE;
    mLayerPaint = layerDisabled ? null : (paint == null ? new Paint() : paint);
    mLocalDirtyRect = layerDisabled ? null : new Rect();
    invalidateParentCaches();
    invalidate(true);
}
复制代码

硬件加速的限制

当我们使用LAYER_TYPE_HARDWARE,我们就得注意硬件加速的限制了。从 Android 3.0(API 级别 11)开始,Android 2D 渲染管道支持硬件加速,如果您的目标 API 级别为 14 及更高级别,则硬件加速默认处于启用状态。 下表介绍了各种绘制操作在各个 API 级别的支持级别:

当我们对自绘控件使用上面的招式时,就要注意是否使用到了表格中不支持的绘制操作,如果用了可以换成LAYER_TYPE_SOFTWARE,但会牺牲掉硬件加速带来的性能提升。

  • 硬件加速官方说明文档:developer.android.com/guide/topic…

    六、一起做裙子

    说了这么多,不放代码是不是很过分:github.com/lenebf/AppD…,对!就是给App穿裙子。除了上面这些效果,我们能够玩的还有很多,比如增强红色,R, G, B互换等。大家有什么问题或者想法可以一起来维护这个Lib,用或者尝试的人越多,暴露出来的问题就越多,等着问题修复后,这个库也就越稳定,以后如果遇到类似的需求,我们用起来就方便了。

作者:lenebf
链接:https://juejin.im/post/6870900334714159111

相关文章

  • 别给APP造轮子了,来穿漂亮的裙子吧

    一、看招 之前在鸿洋的公众号看到App黑白化方案的探索,那叫一个妙,我们先回顾下当时的招式 二、拆招 我们的操作对...

  • 笔小正学书法——上紧下松

    女孩子大都喜欢穿裙子,因为穿裙子漂亮呀。为什么穿裙子漂亮呢?大家一定会说:因为裙子花色漂亮呀!我认为,除了裙子的花...

  • 开源时代,一杯敬明天,一杯敬过往

    Reinvent the Wheel 从“我们不要重复造轮子”到,兄弟们“我们造轮子”吧 不要重复造轮子 意味着我...

  • 2019-05-31 程序员修仙进阶标准,你到哪个阶段了?

    闭门造轮子 > 使用别人的轮子 > 开门造轮子 > 分享轮子

  • 我的裙子漂亮吗

    茜茜穿了一天新裙子,一进幼儿园就来和我炫耀“老师,你看我也这条裙子漂亮吗?” “漂亮的,你裙子怎么这么多的,天天穿...

  • 造了四个轮子之后,我们上路跑一跑

    一、前言 最近相继发布了四个开源项目,都是比较轻量的项目。造完轮子,很自然的想到要弄个App来跑一下。在搬APP出...

  • 造一个方形的轮子11–后记

    造一个方形轮子文章目录:造一个方形的轮子 01、解决遗留问题 最后的最后,来解决一下静态文件的问题吧,这个问题在9...

  • iOS造轮子之引导页

    最近项目刚刚结束,空闲的时间准备跟大神学习造轮子!!今天就造了一个绝大多数app 中都会用到的一个轮子。一个简单的...

  • 造轮子之仿射变换

    有人说,我们不应该再造轮子;也有人说,学习怎么造轮子可以带来更深的理解。我说,用轮子有用轮子的乐趣,造轮子有造轮子...

  • 狐狸小姐的红裙子

    ​狐狸小姐穿了一件红裙子,艳丽很多,漂亮很多,但自从穿了红裙子,生活变了,朋友不小心撒了一点酒水在她裙子上,姐妹们...

网友评论

    本文标题:别给APP造轮子了,来穿漂亮的裙子吧

    本文链接:https://www.haomeiwen.com/subject/rrmryktx.html