Android实现日夜间模式的三种常用方法(一)

 1、使用 setTheme 的方法让 Activity 重新设置主题;

 2、设置 Android Support Library 中的 UiMode 来支持日间/夜间模式的切换;

 3、通过资源 id 映射,回调自定义 ThemeChangeListener 接口来处理日间/夜间模式的切换。



一、使用 setTheme 方法

我们先来看看使用 setTheme 方法来实现日间/夜间模式切换的方案。这种方案的思路很简单,就是在用户选择夜间模式时,Activity 设置成夜间模式的主题,之后再让 Activity 调用 recreate() 方法重新创建一遍就行了。

那就动手吧,在 colors.xml 中定义两组颜色,分别表示日间和夜间的主题色:

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <color name="colorPrimary">#3F51B5</color>
 <color name="colorPrimaryDark">#303F9F</color>
 <color name="colorAccent">#FF4081</color>
 
 <color name="nightColorPrimary">#3b3b3b</color>
 <color name="nightColorPrimaryDark">#383838</color>
 <color name="nightColorAccent">#a72b55</color>
</resources>
之后在 styles.xml 中定义两组主题,也就是日间主题和夜间主题:

<resources>
 
 <!-- Base application theme. -->
 <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
  <!-- Customize your theme here. -->
  <item name="colorPrimary">@color/colorPrimary</item>
  <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
  <item name="colorAccent">@color/colorAccent</item>
  <item name="android:textColor">@android:color/black</item>
  <item name="mainBackground">@android:color/white</item>
 </style>
 
 <style name="NightAppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
  <!-- Customize your theme here. -->
  <item name="colorPrimary">@color/nightColorPrimary</item>
  <item name="colorPrimaryDark">@color/nightColorPrimaryDark</item>
  <item name="colorAccent">@color/nightColorAccent</item>
  <item name="android:textColor">@android:color/white</item>
  <item name="mainBackground">@color/nightColorPrimaryDark</item>
 </style>
 
</resources>
在主题中的  mainBackground  属性是我们自定义的属性,用来表示背景色:

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <attr name="mainBackground" format="color|reference"></attr>
</resources>
接下来就是看一下布局 activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:background="?attr/mainBackground"
 android:paddingBottom="@dimen/activity_vertical_margin"
 android:paddingLeft="@dimen/activity_horizontal_margin"
 android:paddingRight="@dimen/activity_horizontal_margin"
 android:paddingTop="@dimen/activity_vertical_margin"
 tools:context="com.yuqirong.themedemo.MainActivity">
 
 <Button
  android:id="@+id/btn_theme"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:text="切换日/夜间模式" />
 
 <TextView
  android:id="@+id/tv"
  android:layout_below="@id/btn_theme"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:gravity="center_horizontal"
  android:text="通过setTheme()的方法" />
 
</RelativeLayout>
在 <RelativeLayout> 的  android:background  属性中,我们使用 "?attr/mainBackground" 来表示,这样就代表着  RelativeLayout  的背景色会去引用在主题中事先定义好的  mainBackground  属性的值。这样就实现了日间/夜间模式切换的换色了。

最后就是 MainActivity 的代码:

public class MainActivity extends AppCompatActivity {
 
 // 默认是日间模式
 private int theme = R.style.AppTheme;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
 // 判断是否有主题存储
  if(savedInstanceState != null){
   theme = savedInstanceState.getInt("theme");
   setTheme(theme);
  }
  setContentView(R.layout.activity_main);
 
  Button btn_theme = (Button) findViewById(R.id.btn_theme);
  btn_theme.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    theme = (theme == R.style.AppTheme) ? R.style.NightAppTheme : R.style.AppTheme;
    MainActivity.this.recreate();
   }
  });
 }
 
 @Override
 protected void onSaveInstanceState(Bundle outState) {
  super.onSaveInstanceState(outState);
  outState.putInt("theme", theme);
 }
 
 @Override
 protected void onRestoreInstanceState(Bundle savedInstanceState) {
  super.onRestoreInstanceState(savedInstanceState);
  theme = savedInstanceState.getInt("theme");
 }
}

在 MainActivity 中有几点要注意一下:

     1、调用 recreate() 方法后 Activity 的生命周期会调用 onSaveInstanceState(Bundle outState) 来备份相关的数据,之后也会调用 onRestoreInstanceState(Bundle savedInstanceState) 来还原相关的数据,因此我们把 theme 的值保存进去,以便 Activity 重新创建后使用。

     2、我们在 onCreate(Bundle savedInstanceState) 方法中还原得到了 theme 值后,setTheme() 方法一定要在 setContentView() 方法之前调用,否则的话就看不到效果了。

     3、recreate() 方法是在 API 11 中添加进来的,所以在 Android 2.X 中使用会抛异常。

贴完上面的代码之后,我们来看一下该方案实现的效果图:





  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值