4月4日,今天是國家,為了紀念和哀悼為新冠疫情做出努力和犧牲的烈士以及在新冠中逝去的同胞“舉行全國哀悼”的日子!
今天10時全國停止一切娛樂活動,并默哀3分鐘!至此,各大app(愛奇藝、騰訊、虎牙...)響應號召,統一將app主題更換至“哀悼色”...,本篇文章簡談Android端的一種實現方案。
系統api:saveLayer
saveLayer可以為canvas創(chuàng)建一個新的透明圖層,在新的圖層上繪制,并不會直接繪制到屏幕上,而會在restore之后,繪制到上一個圖層或者屏幕上(如果沒有上一個圖層)。為什么會需要一個新的圖層,例如在處理xfermode的時候,原canvas上的圖(包括背景)會影響src和dst的合成,這個時候,使用一個新的透明圖層是一個很好的選擇
public int saveLayer(@Nullable RectF bounds, @Nullable Paint paint, @Saveflags int saveFlags) {
if (bounds == null) {
bounds = new RectF(getClipBounds());
}
checkValidSaveFlags(saveFlags);
return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint,
ALL_SAVE_FLAG);
}
public int saveLayer(@Nullable RectF bounds, @Nullable Paint paint) {
return saveLayer(bounds, paint, ALL_SAVE_FLAG);
}
ColorMatrix中setSaturation設置飽和度,給布局去色(0為灰色,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;
}
1.在view上的實踐
自定義MourningImageVIew
public class MourningImageView extends AppCompatImageView {
private Paint mPaint;
public MourningImageView(Context context) {
this(context,null);
}
public MourningImageView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public MourningImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
createPaint();
}
private void createPaint(){
if(mPaint == null) {
mPaint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
mPaint.setColorFilter(new ColorMatrixColorFilter(cm));
}
}
@Override
public void draw(Canvas canvas) {
createPaint();
canvas.saveLayer(null, mPaint, Canvas.ALL_SAVE_FLAG);
super.draw(canvas);
canvas.restore();
}
@Override
protected void dispatchDraw(Canvas canvas) {
createPaint();
canvas.saveLayer(null, mPaint, Canvas.ALL_SAVE_FLAG);
super.dispatchDraw(canvas);
canvas.restore();
}
}
和普通的ImageView對比效果:

MourningImageView.png
舉一反三在其他的view上也是可以生效的,實際線上項目不可能去替換所有view,接下來我們在根布局上做文章。
自定義各種MourningViewGroup實際替換效果:
<?xml version="1.0" encoding="utf-8"?>
<com.example.sample.MourningLinearlayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical"
>
<ImageView
android:layout_width="wrap_content"
android:src="@mipmap/ic_launcher"
android:layout_margin="20dp"
android:layout_height="wrap_content"/>
<com.example.sample.MourningImageView
android:layout_width="wrap_content"
android:src="@mipmap/ic_launcher"
android:layout_margin="20dp"
android:layout_height="wrap_content"/>
</com.example.sample.MourningLinearlayout>

image.png
也是可以生效的,那接下來的問題就是如何用最少的代碼替換所有的頁面根布局的問題了。在Activity創(chuàng)建的時候同時會創(chuàng)建一個
Window,其中包含一個DecoView,在我們Activity中調用setContentView(),其實就是把它添加到decoView中,可以統一攔截decoview并對其做文章,降低入侵同時減少代碼量。
MourningLinearlayout.png
2.Hook Window DecoView
在application中注冊ActivityLifecycleCallbacks,創(chuàng)建hook點
public class MineApplication extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
//獲取decoview
ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
if(decorView!= null && decorView.getChildCount() > 0) {
//獲取設置的contentview
View child = decorView.getChildAt(0);
//從decoview中移除contentview
decorView.removeView(child);
//創(chuàng)建哀悼主題布局
MourningFramlayout mourningFramlayout = new MourningFramlayout(activity);
//將contentview添加到哀悼布局中
mourningFramlayout.addView(child);
//將哀悼布局添加到decoview中
decorView.addView(mourningFramlayout);
}
...
}
找個之前做的項目試試效果:

HistoryProject.png
效果還行,暫時沒發(fā)現什么坑,但是可能存在坑....??????