目前市面上流行的APP都会在国家哀悼日切换成黑白模式。我司APP之前的处理方式只是让后台把网络图片处理成黑白色,前段时间接到需求,要求把APP界面的其他地方也切换成黑白,比方说这些地方:

最暴力的做法当然就是准备两套切图,根据条件手动替换切图。但界面需要替换的地方很多,这样做太不优雅(想起了当年做夜间模式切换两套皮肤资源的恐惧)。
然后我就想起了ColorMatrix这个可以进行色彩处理的矩阵类,其中比较关键的是这个饱和度处理的方法setSaturation

虽然矩阵变换的原理已经基本还给老师了,但是根据方法的描述,我们还是可以知道,传0进去是可以变成灰度图像的,一般情况下,我们还要配合Paint类和Canvas类来使用,如下可以绘制一张Bitmap图片的灰度图

那么问题来了,这里只是处理Bitmap而已,我们的需求是要把ImageView、TextView、Button等控件变成黑白模式,那应该怎么处理呢?
比较容易想到的是继承这些View,并重写draw()方法。其中,Canvas.saveLayer()这个方法,它的作用是生成一个新的层,这个层是透明的,之后所有的绘制操作都会再这个层上进行,通过传入我们提前设置好灰度变换的mPaint,再调用super.draw(canvas)绘制图像,最后通过Canvas.retore()把图像绘制到原来的Canvas层上,以此实现了我们对View的灰度变换。

那么问题又来了,如果每个ImageView、TextView都替换成自定义View,那工作量比替换图片资源就更大了,有没有一种可以动态把View变换成黑白的方式呢?百思不得其解之下,我选择了搜索引擎,果然,网上有大神提出了一种方案,通过调用view的setLayerType方法开启硬件加速,并传入paint进行灰度变换
view.setLayerType(View.LAYER_TYPE_HARDWARE, paint);

至此,我们实现了动态对单个View进行灰度变换,然后只需解决最后的问题,我们如果对整个界面进行灰度变换呢?这时候需要搬出一张老掉牙的图

在我们界面的布局rootView上面的是DecorView,只要在Activity适当的地方调用getWindow().getDecorView()就可以获取DecorView,然后对DecorView调用setLayerType(View.LAYER_TYPE_HARDWARE, paint)方法,就可以实现整个界面的灰度变换,最终效果

