真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

AndroidAPP全局黑白化實(shí)現(xiàn)方案-創(chuàng)新互聯(lián)

在清明節(jié)時(shí)各大APP都會(huì)進(jìn)行黑白化處理,當(dāng)時(shí)在接到這個(gè)需求的時(shí)候感覺(jué)好麻煩,是不是又要搞一套皮膚?

創(chuàng)新互聯(lián)建站從2013年成立,先為施秉等服務(wù)建站,施秉等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為施秉企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。

然而在一系列搜索之后,找到了兩位大神(鴻洋、U2tzJTNE)的實(shí)現(xiàn)方案,其實(shí)相當(dāng)?shù)暮?jiǎn)單!

讓我們一起站在巨人的肩膀上來(lái)分析一下原理,并思考會(huì)不會(huì)有更簡(jiǎn)便的實(shí)現(xiàn)?

一、原理

兩位大神的置灰方案是相同的,都能看到一段同樣的代碼:

Paint mPaint = new Paint();
ColorMatrix mColorMatrix = new ColorMatrix();
// 設(shè)置飽和度為0
mColorMatrix.setSaturation(0);
mPaint.setColorFilter(new ColorMatrixColorFilter(mColorMatrix));

他們都用了Android提供的ColorMatrix(顏色矩陣),將其飽和度設(shè)置為0,這樣使用Paint繪制出來(lái)的都是沒(méi)有飽和度的灰白樣式!

然而兩位在何時(shí)使用Paint繪制時(shí)選擇了不同方案。

1.1 鴻洋:重寫draw方法

鴻洋分析,如果我們把每個(gè)Activity的根布局飽和度設(shè)置為0是不是就可以了?

那根布局是誰(shuí)?

鴻洋分析我們的布局最后setContentView最后都會(huì)設(shè)置到一個(gè)R.id.content的FrameLayout當(dāng)中。

我們?nèi)プ远x一個(gè)GrayFrameLayout,在draw的時(shí)候使用這個(gè)飽和度為0的畫筆,被這個(gè)FrameLayout包裹的布局都會(huì)變成黑白。

// 轉(zhuǎn)載自鴻洋
// https://blog.csdn.net/lmj623565791/article/details/105319752
public class GrayFrameLayout extends FrameLayout {
    private Paint mPaint = new Paint();

    public GrayFrameLayout(Context context, AttributeSet attrs) {
        super(context, attrs);

        ColorMatrix cm = new ColorMatrix();
        cm.setSaturation(0);
        mPaint.setColorFilter(new ColorMatrixColorFilter(cm));
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.saveLayer(null, mPaint, Canvas.ALL_SAVE_FLAG);
        super.dispatchDraw(canvas);
        canvas.restore();
    }

    @Override
    public void draw(Canvas canvas) {
        canvas.saveLayer(null, mPaint, Canvas.ALL_SAVE_FLAG);
        super.draw(canvas);
        canvas.restore();
    }
}

然后我們用GrayFrameLayout去替換這個(gè)R.id.content的FrameLayout,是不是就可以做到將頁(yè)面黑白化了?

替換FrameLayout的方法可以去【鴻洋】這篇文章下查看。

1.2 U2tzJTNE:監(jiān)聽DecorView的添加

U2tzJTNE大佬 使用了另一種巧妙的方案。

他先創(chuàng)建了一個(gè)具有數(shù)據(jù)變化感知能力的ObservableArrayList(當(dāng)內(nèi)容發(fā)生變化有回調(diào))。

之后使用反射將WindowManagerGlobal內(nèi)的mViews容器(ArrayList,該容器會(huì)存放所有的DecorView),替換為ObservableArrayList,這樣就可以監(jiān)聽到每個(gè)DecorView的創(chuàng)建,并且拿到View本身。

拿到DecorView,那就可以為所欲為了!

大佬使用了setLayerType(View.LAYER_TYPE_HARDWARE, mPaint),對(duì)布局進(jìn)行了重繪。至于為什么要用LAYER_TYPE_HARDWARE?因?yàn)槟J(rèn)的View.LAYER_TYPE_NONE會(huì)把Paint強(qiáng)制設(shè)置為null。

// 轉(zhuǎn)載自U2tzJTNE
// https://juejin.cn/post/6892277675012915207
public static void enable(boolean enable) {
    try {
        //灰色調(diào)Paint
        final Paint mPaint = new Paint();
        ColorMatrix mColorMatrix = new ColorMatrix();
        mColorMatrix.setSaturation(enable ? 0 : 1);
        mPaint.setColorFilter(new ColorMatrixColorFilter(mColorMatrix));

        //反射獲取windowManagerGlobal
        @SuppressLint("PrivateApi")
        ClasswindowManagerGlobal = Class.forName("android.view.WindowManagerGlobal");
        @SuppressLint("DiscouragedPrivateApi")
        java.lang.reflect.Method getInstanceMethod = windowManagerGlobal.getDeclaredMethod("getInstance");
        getInstanceMethod.setAccessible(true);
        Object windowManagerGlobalInstance = getInstanceMethod.invoke(windowManagerGlobal);

        //反射獲取mViews
        Field mViewsField = windowManagerGlobal.getDeclaredField("mViews");
        mViewsField.setAccessible(true);
        Object mViewsObject = mViewsField.get(windowManagerGlobalInstance);

        //創(chuàng)建具有數(shù)據(jù)感知能力的ObservableArrayList
        ObservableArrayListobserverArrayList = new ObservableArrayList<>();
        observerArrayList.addOnListChangedListener(new ObservableArrayList.OnListChangeListener() {
            @Override
            public void onChange(ArrayList list, int index, int count) {
            }

            @Override
            public void onAdd(ArrayList list, int start, int count) {
            	// 拿到DecorView觸發(fā)重繪
                View view = (View) list.get(start);
                if (view != null) {
                    view.setLayerType(View.LAYER_TYPE_HARDWARE, mPaint);
                }
            }

            @Override
            public void onRemove(ArrayList list, int start, int count) {
            }
        });
        //將原有的數(shù)據(jù)添加到新創(chuàng)建的list
        observerArrayList.addAll((ArrayList) mViewsObject);
        //替換掉原有的mViews
        mViewsField.set(windowManagerGlobalInstance, observerArrayList);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

只需要在Application里面調(diào)用該方法即可。

1.3 方案分析

兩位大佬的方案都非常的棒,咱們理性的來(lái)對(duì)比一下。

  • 鴻洋: 使用自定義FrameLayout的方案需要一個(gè)BaseActivity統(tǒng)一設(shè)置,稍顯麻煩,代碼侵入性較強(qiáng)。

  • U2tzJTNE: 方案更加簡(jiǎn)單、動(dòng)態(tài),一行代碼設(shè)置甚至可以做到在當(dāng)前頁(yè)從彩色變黑白,但是使用了反射,有一點(diǎn)點(diǎn)性能消耗。

二、簡(jiǎn)易方案(直接復(fù)制)

既然研究明白了大佬的方案,那有沒(méi)有又不需要反射,設(shè)置又簡(jiǎn)單的方法呢?

能不能使用原生方式獲取DecorView的實(shí)例呢?

突然靈光一閃,Application里面不是有registerActivityLifecycleCallbacks這個(gè)注冊(cè)監(jiān)聽方法嗎?監(jiān)聽里面的onActivityCreated不是可以獲取到當(dāng)前的Activity嗎?那DecorView不就拿到了!

搞起!上代碼!

public class StudyApp extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        Paint mPaint = new Paint();
        ColorMatrix mColorMatrix = new ColorMatrix();
        mColorMatrix.setSaturation(0);
        mPaint.setColorFilter(new ColorMatrixColorFilter(mColorMatrix));

        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {

            @Override
            public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
            	// 當(dāng)Activity創(chuàng)建,我們拿到DecorView,使用Paint進(jìn)行重繪
                View decorView = activity.getWindow().getDecorView();
                decorView.setLayerType(View.LAYER_TYPE_HARDWARE, mPaint);
            }

			....
        });
    }
}

這樣看起來(lái)是不是更簡(jiǎn)單了!使用了APP原生的方法實(shí)現(xiàn)了黑白化!當(dāng)然也有缺點(diǎn),因?yàn)樵贏ctivity級(jí)別設(shè)置,無(wú)法做到在當(dāng)前頁(yè)面即時(shí)變?yōu)楹诎住?/p>三、注意事項(xiàng)

這三種方案因?yàn)槎际褂昧祟伾仃?,所以坑都是一樣的,?qǐng)注意。

3.1 啟動(dòng)圖windowBackground無(wú)法變色

在我們可以設(shè)置渲染的時(shí)候windowBackground已經(jīng)展示完畢了。

解決方案:只能在當(dāng)前的包里修改,或者不去理會(huì)。

3.2 SurfaceView無(wú)法變色

因?yàn)槲覀兪褂昧藄etLayerType進(jìn)行重繪,而SurfaceView是有獨(dú)立的Window,脫離布局內(nèi)的Window,運(yùn)行在其他線程,不影響主線程的繪制,所以當(dāng)前方案無(wú)法使SurfaceView變色。

解決方案:
1、使用TextureView。
2、看下這個(gè)SurfaceView是否可以設(shè)置濾鏡,正常都是一些三方或者自制的播放器。

3.3 多進(jìn)程變色

我們可能會(huì)在APP內(nèi)置小程序,小程序基本是運(yùn)行在單獨(dú)的進(jìn)程中,但是如果我們的黑白配置在運(yùn)行過(guò)程中發(fā)生變化,其他進(jìn)程是無(wú)法感知的。

解決方案:使用 MMKV 存儲(chǔ)黑白配置,并設(shè)置多進(jìn)程共享,在開啟小程序之前都判斷一下黑白展示。

總結(jié)

最后咱們?cè)倏偨Y(jié)一下黑白化方案。

使用了ColorMatrix設(shè)置飽和度為0,設(shè)置到Paint中,讓根布局拿著這個(gè)Paint去進(jìn)行重繪。

這樣APP全局黑白化的介紹就結(jié)束了,希望大家讀完這篇文章,會(huì)對(duì)APP黑白化有一個(gè)更深入的了解。如果我的文章能給大家?guī)?lái)一點(diǎn)點(diǎn)的福利,那在下就足夠開心了。

更多Android 知識(shí)點(diǎn)歸整

Android 性能調(diào)優(yōu)系列:https://0a.fit/dNHYY

Android 車載學(xué)習(xí)指南:https://0a.fit/jdVoy

Android Framework核心知識(shí)點(diǎn)筆記:https://0a.fit/acnLL

Android 音視頻學(xué)習(xí)筆記:https://0a.fit/BzPVh

Jetpack全家桶(含Compose):https://0a.fit/GQJSl

Kotlin 入門到精進(jìn):https://0a.fit/kdfWR

Flutter 基礎(chǔ)到進(jìn)階實(shí)戰(zhàn):https://0a.fit/xvcHV

Android 八大知識(shí)體系:https://0a.fit/mieWJ

Android 中高級(jí)面試題錦:https://0a.fit/YXwVq

后續(xù)如有新知識(shí)點(diǎn),將會(huì)持續(xù)更新,盡請(qǐng)期待……

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧


標(biāo)題名稱:AndroidAPP全局黑白化實(shí)現(xiàn)方案-創(chuàng)新互聯(lián)
本文URL:http://weahome.cn/article/cdicgp.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部