1. First of all, let’s look at the comparison of the effect without and after greying

 

2. Implement logic

First let’s look at the layout



Our first approach is to do it with the idea of layout replacement

So the first thing we can see is the id/content content framelayout and our goal is to replace that

Let’s customize a FrameLayout code as follows:

class GrayFrameLayout( context: Context, attrs: AttributeSet? ) : FrameLayout(context, attrs) {private val paint: paint /** * @param canvas */ override fun draw(canvas: Canvas) { canvas.saveLayer(null, paint, Canvas.ALL_SAVE_FLAG) super.draw(Canvas) Canvas. Restore ()} /** * Draw child control * @param Canvas */ Override fun dispatchDraw(canvas: Canvas) { canvas.saveLayer(null, paint, Canvas.ALL_SAVE_FLAG) super.dispatchDraw(canvas) canvas.restore() } init { paint = Paint() val colorMatrixColorFilter =ColorMatrixColorFilter(MatrixArrays.gray_matrix) paint.colorFilter = colorMatrixColorFilter } }Copy the code
/** ** / val gray_matrix =floatArrayOf(0.33f, 0.59f, 0.11f, 0f, 0f, 0.33f, 0.59f, 0.11f, 0f, 0f, 0.33f, 0.59f, 0.11f, 0f, 0f, 0f, 1f, ArrayOf(0.33f, 0.59f, 0.11f, 0f, 0f, 0f, 0f, 1f, 0f) so that we can achieve layout including layout controls have gray effect, the next step is our replacement stepCopy the code

1. If your BaseActivity inherits from an Activity, here's your replacement flow using the layout loader in the BaseActivity onCreate method: LayoutInflaterCompat. SetFactory2 (layoutInflater, GrayFactory ()) as follows: (1) GrayFactory code class GrayFactory: Override Fun onCreateView(parent: View? , name: String, context: Context, attrs: AttributeSet ): View? {if (TextUtils.equals("FrameLayout", name)) {            
        val attributeCount = attrs.attributeCount            
    for (i in 0 until attributeCount) {                
        val attributeName = attrs.getAttributeName(i)                
        val attributeValue = attrs.getAttributeValue(i)                
            if (TextUtils.equals("id". attributeName)) { val id = attributeValue.substring(1).toInt() val resourceName = context.resources.getResourceName(id)if (TextUtils.equals("android:id/content", resourceName)) {                        
                             returnGrayFrameLayout(context, attrs) // Create GrayFrameLayout}}}}return onCreateView(name, context, attrs)    
}    
override fun onCreateView(        
name: String,        
context: Context,        
attrs: AttributeSet    ): View? {        
var view: View? = null        
try {            
val aClass = context.classLoader.loadClass(name)            
val constructor: Constructor<out View> =                
                    aClass.getConstructor(                    
                    Context::class.java, AttributeSet::class.java                
                    ) as Constructor<out View>            
view = constructor.newInstance(context, attrs)        
} 
catch (e: ClassNotFoundException) {            
e.printStackTrace()        
} 
catch (e: NoSuchMethodException) {            
e.printStackTrace()        } 
catch (e: IllegalAccessException) {            
e.printStackTrace()        } 
catch (e: InstantiationException) {            
e.printStackTrace()        } 
catch (e: InvocationTargetException) {            
e.printStackTrace()        }        
return view    
    }
}
Copy the code

If you have a BaseActivity that inherits AppCompatActivity, the following is the compatactivity's replacement process, which is simplified in the BaseActivity onCreateView method:if (TextUtils.equals("FrameLayout", name)) {
        val attributeCount = attrs.attributeCount
        for (i in 0 until attributeCount) {
            val attributeName = attrs.getAttributeName(i)
            val attributeValue = attrs.getAttributeValue(i)
            if (TextUtils.equals("id". attributeName)) { val id = attributeValue.substring(1).toInt() val resourceName = context.resources.getResourceName(id)if (TextUtils.equals("android:id/content", resourceName)) {
                    returnGrayFrameLayout(context, attrs) // Create GrayFrameLayout}}}}returnSuper.oncreateview (name, context, attrs)// Must be called super, this is prone to endless loopCopy the code

Our second approach is to use the idea of layout substitution

First we see that the root layout above is a DecorView and our purpose is to replace it

① We add it in the BaseActivity onCreat method

var decorView = window.decorViewvar var paint = Paint() val colorMatrixColorFilter = ColorMatrixColorFilter(MatrixArrays.gray_matrix) paint.colorFilter = colorMatrixColorFilter Decorview.setlayertype (view.layer_type_hardware,paint)// Remember to turn on hardware acceleration in the manifest file. ColorMatrix cm = new ColorMatrix(); cm.setSaturation(0); SetColorFilter (new ColorMatrixColorFilter(cm)); activity.getWindow().getDecorView().setLayerType(View.LAYER_TYPE_HARDWARE, paint);Copy the code

You may notice that the Dialog effect is not greyed:

Solution: The second implementation of the first method is used in conjunction with the second method

Conclusion:

This article mainly uses the layout replacement. Every interface in the project has the same system root layout DecorView, ContentFrameLayout, so start with this to see the source code more clearly