Android主題切換之探究白天和夜間模式_Android

來源:互聯網
上載者:User

智能手機的迅速普及,大大的豐富了我們的娛樂生活。現在大家都喜歡晚上睡覺前玩會兒手機,但是應用的日間模式往往亮度太大,對眼睛有較為嚴重的傷害。因此,如今的應用往往開發了 日間和夜間 兩種模式供使用者切換使用,那日間和夜間模式切換究竟是怎樣實現的呢?

在文字類的App上面基本上都會涉及到夜間模式、就是能夠根據不同的設定、呈現不同風格的介面給使用者、而且晚上看著不傷眼睛、實現方式也就是所謂的換膚(主題切換)、對於夜間模式的實現網上流傳了很多種方式、這裡先分享一個方法給大家、通過設定背景為透明的方法、降低螢幕的亮度與色度。


夜間模式代碼

public void night() {  WindowManager.LayoutParams params = new WindowManager.LayoutParams(      LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,      LayoutParams.TYPE_APPLICATION,      WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE          | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,      PixelFormat.TRANSLUCENT);  params.gravity=Gravity.BOTTOM;  params.y=10;  if(myView==null){    myView=new TextView(this);    myView.setBackgroundColor(0x80000000);  }  mWindowManager.addView(myView, params);  Editor edit = skinSp.edit();  edit.putString("skin", NIGHT);  edit.commit();}

白天模式

public void day(){  if(myView!=null){    mWindowManager.removeView(myView);    Editor edit = skinSp.edit();    edit.putString("skin", DAY);    edit.commit();  }}

下面通過執行個體操作來詳細展示如何進行Android主題切換中的白天/夜間模式。

上述兩幅圖片,正是兩款App的夜間模式效果,所以,依據這個功能,來看看切換主題到底是怎麼實現的(當然現在github有好多PluginTheme開源外掛程式,很多時候可以使用這些外掛程式,不過我並不想講怎麼用那些外掛程式,正所謂會用輪子還不如會造輪子)。

關於更換主題和換膚

這裡提到是做換主題功能,當然與之類似的就是換膚,換膚現在比較流行的是採用外掛程式化動態載入技術來實現的,這樣可以起到熱插拔作用,需要皮膚時候使用者自主的在網上下載便是了,不用皮膚時便刪了皮膚外掛程式包而不會影響宿主App的功能,這樣就不必把一大堆皮膚圖片放在本地而增加apk的大小,關於用外掛程式化實現換膚功能這僅僅是外掛程式化技術的冰山一角,關於外掛程式化技術更多的作用,可以看看360前兩天開源的 DroidPlugin外掛程式架構、OpenAltas架構、還有主席的DL架構。

好了,言歸正傳,現在我們需要實現的是主題切換功能,關於主題切換其實是切換整個App的顏色風格、排版風格、字型風格等,其中並不會有過多的圖片資源的切換,如有過多的圖片的更換那就是換膚的功能了。
現在我們要實現夜間/白天模式的切換功能,如下效果圖:


可以看到上面的效果正是夜間和白天兩種模式的切換功能,切換至夜間模式時整個App的背景色、字型顏色、按鈕顏色、標題列顏色等全部需要切為夜間模式的顏色,當切回白天模式又切回原來的顏色,來看看怎麼做的?

實現主題切換

首先就是需要在app中準備兩套主題:

白天主題

<resources>  <style name="DayTheme" parent="Theme.AppCompat.Light.DarkActionBar">    <!-- Customize your theme here. -->    <item name="colorPrimary">#03A9F4</item>    <item name="android:textColorPrimary">#ffffff</item>    <item name="android:windowBackground">@color/background_material_light</item>    <item name="colorAccent">#00BCD4</item>    <item name="colorControlNormal">#00BCD4</item>    <item name="titleStyle">@style/DayTitleStyle</item>    <item name="contentStyle">@style/DayContentStyle</item>    <item name="buttonBg">#2196F3</item>    <item name="buttonTextColor">#ffffff</item>    <item name="checkTextColor">#2196F3</item>    <item name="switchTextColor">#2196F3</item>  </style>  <style name="DayTitleStyle">    <item name="android:textColor">#212121</item>    <item name="android:textSize">20sp</item>    <item name="android:layout_margin">8dp</item>  </style>  <style name="DayContentStyle">    <item name="android:textColor">#9C27B0</item>    <item name="android:textSize">16sp</item>    <item name="android:layout_margin">16dp</item>    <item name="android:maxLines">10</item>  </style></resources>

夜間主題

<resources>  <style name="NightTheme" parent="Theme.AppCompat.Light.DarkActionBar">    <!-- Customize your theme here. -->    <item name="colorPrimary">#00796B</item>    <item name="android:textColorPrimary">#212121</item>    <item name="android:windowBackground">@color/background_material_dark</item>    <item name="colorAccent">#00796B</item>    <item name="colorControlNormal">#212121</item>    <item name="titleStyle">@style/NightTitleStyle</item>    <item name="contentStyle">@style/NightContentStyle</item>    <item name="buttonBg">#00796B</item>    <item name="buttonTextColor">#9E9E9E</item>    <item name="checkTextColor">#212121</item>    <item name="switchTextColor">#212121</item>  </style>  <style name="NightTitleStyle">    <item name="android:textColor">#212121</item>    <item name="android:textSize">20sp</item>    <item name="android:layout_margin">8dp</item>  </style>  <style name="NightContentStyle">    <item name="android:textColor">#212121</item>    <item name="android:textSize">16sp</item>    <item name="android:layout_margin">16dp</item>    <item name="android:maxLines">10</item>  </style></resources>

上面這兩套主題中,各個屬性定義完全一模一樣,不一樣的只是屬性的值,其中在DayTheme和NightTheme的style中有這麼一段代碼:

<item name="titleStyle">@style/DayTitleStyle</item><item name="contentStyle">@style/DayContentStyle</item><item name="buttonBg">#2196F3</item><item name="buttonTextColor">#ffffff</item><item name="checkTextColor">#2196F3</item><item name="switchTextColor">#2196F3</item>

正常情況下style中是不存在這些屬性的,它們這些是自訂屬性,主要是用來控制某些控制項或者布局的屬性,它們的定義在attr檔案中:

<?xml version="1.0" encoding="utf-8"?><resources>  <attr name="contentStyle" format="reference"/>  <attr name="titleStyle" format="reference"/>  <attr name="buttonBg" format="reference|color"/>  <attr name="buttonTextColor" format="reference|color"/>  <attr name="checkTextColor" format="reference|color"/>  <attr name="switchTextColor" format="reference|color"/></resources>

然後在布局中引用即可:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  xmlns:tools="http://schemas.android.com/tools"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:orientation="vertical"  tools:context=".MainActivity">  <TextView    style="?attr/titleStyle"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:text="@string/title" />  <TextView    style="?attr/contentStyle"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:text="@string/hello_world" />  <CheckBox    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:text="CheckBox"    android:textColor="?attr/checkTextColor" />  <CheckBox    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:text="CheckBox"    android:textColor="?attr/checkTextColor" />  <Switch    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:text="Switch"    android:textColor="?attr/switchTextColor" />  <Button    android:id="@+id/btn_setting"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:text="設定"    android:background="?attr/buttonBg"    android:textColor="?attr/buttonTextColor" /></LinearLayout>

最後在整個App主題的style中使用它們就ok了。這樣做有什麼好處呢?我們都知道App設定主題時候都是設定一個style,而App中某些控制項或者布局的背景或者style樣式需要和整個主題樣式不同時,這時候可以通過設定個自訂屬性,通過在App的style中給與自訂屬性不同的值來達到目的。

切換主題

好了,有了兩套主題了,接下來是通過代碼來進行控制主題間的切換了,控制主題的切換其實就是通過setTheme(R.style.*);來設定不同的style從而達到介面風格的變換,不過這個方法setTheme()只在setContentView()方法前設定才有效,所以如果你想在其它地方調用這個方法來切換主題那是肯定不行的,所以這裡有兩個痛點?

1、怎麼處理當前的設定介面在切換主題後同時切換主題風格

2、怎麼處理之前已經開啟的介面讓他們切換主題風格

這裡我給出的答案是:

1、在當前切換主題的設定介面使用Activity.recreate()方法,該方法的作用就是噹噹前Activity的配置發生變化時,調用這個方法可以把當前Activity執行個體銷毀並重新建立出一個Activity執行個體。如此可見通過這個方法可以很容易的解決問題一,因為它會重新建立一個新的Activity執行個體。

2、這裡我使用的方法是通過設定Intent的Flag來達到更新之前Activity的效果,通過設定mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);讓它清除之前的Activity再建立一個新的Activity,這樣當返回之前的介面就可以更新主題了。【注】如果有多個介面可以通過設定主介面MainActivity的launchMode為singleTask,在返回主介面時候清除其它介面來更新主題

對於上面的方法(如有更好的方法歡迎告知,萬分感謝!)

代碼實現

最後再貼下代碼:
通過一個主題設定工具類設定主題,在每個Activity的setContentView()方法之前設定主題:
設定主題工具類:

public class ThemeChangeUtil {  public static boolean isChange = false;  public static void changeTheme(Activity activity){    if(isChange){      activity.setTheme(R.style.NightTheme);    }  }}

設定介面:

public class ChangeTheme extends AppCompatActivity {  @Override  protected void onCreate(Bundle savedInstanceState) {    ThemeChangeUtil.changeTheme(this);    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_change);    Button mChangeBtn = (Button) findViewById(R.id.btn_change);    mChangeBtn.setOnClickListener(new View.OnClickListener() {      @Override      public void onClick(View v) {        if (ThemeChangeUtil.isChange) {          ThemeChangeUtil.isChange = false;        } else {          ThemeChangeUtil.isChange = true;        }        ChangeTheme.this.recreate();//重新建立當前Activity執行個體      }    });  }  @Override  public void onBackPressed() {    super.onBackPressed();    Intent mIntent = new Intent(this, MainActivity.class);    mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);    startActivity(mIntent);    finish();  }}

主介面:

public class MainActivity extends AppCompatActivity {  @Override  protected void onCreate(Bundle savedInstanceState) {    ThemeChangeUtil.changeTheme(this);    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    Button mSettingBtn = (Button) findViewById(R.id.btn_setting);    mSettingBtn.setOnClickListener(new View.OnClickListener() {      @Override      public void onClick(View v) {        MainActivity.this.startActivity(new Intent(MainActivity.this, ChangeTheme.class));      }    });  }}

以上就是Android主題切換中的白天/夜間模式的詳細過程及代碼,一開始先給大家簡單的展示了代碼,而後詳細的介紹過程及代碼,需要的朋友參考。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.