Android 灰白化處理(清明節效果 多種方法簡單實現)

  1. 首先看下沒有灰白化的和灰白化後的效果對比

 

2.實現邏輯java

首先咱們看下佈局的android


咱們第一種方法就是用佈局替換的思惟去實現canvas

首先咱們能看到id/content的ContentFrameLayout咱們的目的就是替換他bash

咱們去自定義一個 FrameLayout代碼以下:ide

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()    
}    
/**     
* 繪製子控件     
* @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    
    }
}複製代碼
MatrixArrays.gray_matrix是用矩陣實現的灰白效果
/** 
* 灰白 
*/
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, 0f, 0f, 1f, 0f)這樣咱們就能夠實現佈局包括佈局內的控件都有灰白的效果,下一步就是咱們的替換步驟了
複製代碼

一、若是你的BaseActivity繼承的是Activity那下面的就你的替換流程
咱們利用佈局加載器在BaseActivity的onCreate方法中:
LayoutInflaterCompat.setFactory2(layoutInflater,GrayFactory())①GrayFactory代碼以下:
class GrayFactory : Factory2 {    
//Android5.0以前繼承activity的灰白化處理    
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)) {                        
                             return GrayFrameLayout(context, attrs) //建立灰白化framelayout                    
                }                
            }            
        }        
    }        
    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    
    }
}
複製代碼

二、若是你的BaseActivity繼承的是AppCompatActivity那下面的就你的替換流程:就是把上面的簡化了
在BaseActivity的onCreateView方法中:
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)) {
                    return GrayFrameLayout(context, attrs) //建立灰白化framelayout
                }
            }
        }
    }
return super.onCreateView(name, context, attrs)//必定是調super的,這裏容易出現死循環
複製代碼

咱們第二種方法就是用佈局替換的思惟去實現佈局

首先咱們看到上面的最根的根佈局是DecorView咱們的目的就是替換他ui

①咱們在BaseActivity的onCreat方法中添加spa

var decorView = window.decorViewvar
var paint = Paint()
val colorMatrixColorFilter =    ColorMatrixColorFilter(MatrixArrays.gray_matrix)
paint.colorFilter = colorMatrixColorFilter
decorView.setLayerType(View.LAYER_TYPE_HARDWARE,paint)//記得在清單文件中打開硬件加速

還有一種實現//不用矩陣計算用系統自帶的
 Paint paint = new Paint();
            ColorMatrix cm = new ColorMatrix();
            cm.setSaturation(0);//0就是灰白效果
            paint.setColorFilter(new ColorMatrixColorFilter(cm));
            activity.getWindow().getDecorView().setLayerType(View.LAYER_TYPE_HARDWARE, paint);複製代碼

在使用的過程當中可能會發現dialog效果沒有實現灰白化:3d

處理方法:第一種方法的第二個實現和第二種一塊兒使用就能夠了rest

結尾總結:

本文主要用到的是佈局替換,項目中每一個界面都有相同的系統根佈局DecorView、ContentFrameLayout因此從這裏入手這個能夠看下源碼更清楚