1. 程式人生 > >【Android】仿知乎夜間模式的實現

【Android】仿知乎夜間模式的實現

1.簡介

目前很多App都有夜間模式的功能,網上教程也是很多,最近專案不忙,抽空學習了下,在這做下記錄,希望能幫到正在看部落格的你,我們先來看下知乎的效果:

這裡寫圖片描述

看我的效果:

這裡寫圖片描述

臥槽,好像啊,哈哈,好吧,有點神似,關於知乎實現的分析,大家可以看下這位大神的分析,那咱們廢話少說,開始實現吧。

2.AppCompatDelegate方式實現

在support.v7包中google提供了AppCompatDelegate類,可以用於實現夜間模式,實現起來比較簡單:

一、設定Activity主題,繼承自Theme.AppCompat.DayNight等夜間相關的主題

<style
name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">

二、通過setDefaultNightMode(Mode)方法來設定當前的模式

AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);

該模式有三種

  • AppCompatDelegate.MODE_NIGHT_AUTO,他會時刻知道你最後的位置和時間(如果您的應用程式已開啟位置許可權)用於白天和黑夜之間自動切換的 依據
  • AppCompatDelegate.MODE_NIGHT_NO 強制設定了從不使用夜晚主題。
  • AppCompatDelegate.MODE_NIGHT_YES 則強制設定了一直使用夜晚主題。

以上來自模式介紹.

三、通過在res目錄下建立value-night,drawable-night等目錄來進行匹配,當設定為夜間模式的時候,會取-night下的資源,反之,會取預設的資源,看下效果:

這裡寫圖片描述

以上實現的是白天和夜間分別載入不同的圖片和background,不過使用這種方式有個問題,就是如果設定夜間模式後,不進行跳轉,本頁面要想有反應必須呼叫activity的recreate()方法,會出現閃屏問題,所以雖然實現簡單,但是效果並不好,這裡不再過多介紹,原始碼下載文末給出。

3.仿知乎夜間模式的實現

思路借鑑上文對知乎分析文章的介紹,首先製造出一個和當前頁面一樣的ImageView放在頁面的最上層,然後切換夜間模式時,設定需要設定的顏色,背景等屬性,然後對ImageView進行顏色漸變的實現,使其看起來更平滑,說的有點亂,看具體步驟:

一、獲取佈局檔案最外層Layout的截圖

/**
     * 獲取view截圖對應的bitmap
     * @param v
     * @return
     */
    public Bitmap loadBitmapFromView(View v) {
        //width為螢幕寬度,height為螢幕高度,statusBarHeight為狀態列高度
        Bitmap b = Bitmap.createBitmap(width, height-statusBarHeight, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(b);
        v.layout(0, 0, v.getLayoutParams().width, v.getLayoutParams().height);
        v.draw(c);
        return b;
    }

二、建立臨時的ImageView並add到rootLayout中

final ImageView imageView = new ImageView(this);
imageView.setLayoutParams(new ViewGroup.LayoutParams(width, height-statusBarHeight));
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
Bitmap bitmap = loadBitmapFromView(rootLayout);
imageView.setImageBitmap(bitmap);
rootLayout.addView(imageView);

四、設定夜間/日間模式

/**
     * 設定日漸模式具體程式碼
     */
    private void setDayThemeInfo() {
        rootLayout.setBackgroundColor(Color.parseColor("#FFFFFF"));
        tvColor.setTextColor(Color.parseColor("#222222"));
        imageView.setImageResource(R.mipmap.day_icom);
    }

/**
     * 設定夜間模式具體程式碼
     */
    private void setNightThemeInfo() {
        rootLayout.setBackgroundColor(Color.parseColor("#333444"));
        tvColor.setTextColor(Color.parseColor("#666666"));
        imageView.setImageResource(R.mipmap.night_icon);
    }

五、漸變動畫,移除臨時的ImageView

        int colorA = Color.parseColor("#ffffff");
        int colorB = Color.parseColor("#333444");
        ObjectAnimator objectAnimator = ObjectAnimator.ofInt(imageView, "backgroundColor", colorA, colorB);
        objectAnimator.setDuration(800);
        objectAnimator.setEvaluator(new ArgbEvaluator());
        objectAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                rootLayout.removeView(imageView);
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        objectAnimator.start();

在以上介紹中,省略了一些簡單的步驟,比如獲取螢幕寬高,佈局檔案也沒有貼出來,實際專案中肯定還需要儲存當前的模式,一般使用SharedPreferences儲存即可,然後初始化的時候載入相應的設定主題的程式碼,不再敖述。

這裡寫圖片描述

本文旨在給出一些基本的思路和簡單實現,具體使用中還需對細節進行處理,望各位看官注意!

這裡寫圖片描述