网上查找资料,切换主题常见大概有三种方式,参考关于三种『应用内主题切换』开源项目的一点思考 ,但是我这里用最简单的一种来实践。如下:
使用重启Activity来加载主题
新建attrs.xml
新建values/attrs.xml来实现我们切换主题需要改变的属性比如:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="btnBgColor" format="color"/>
<attr name="btnTxColor" format="color"/>
</resources>
这里新建了两个属性来改变Button的文字颜色和背景颜色
新建style
在values/styles.xml中新建两个主题样式
<!-- 日间 -->
<style name="AppTheme_Light" 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>
<!-- Button文字为黑色 -->
<item name="btnTxColor">#000000</item>
<!-- Button文字为白色-->
<item name="btnBgColor">#ffffff</item>
</style>
<!-- 夜间 -->
<style name="AppTheme_Night" 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>
<!-- Button文字为白色 -->
<item name="btnTxColor">#ffffff</item>
<!-- Button文字为黑色 -->![这里写图片描述](https://img-blog.csdn.net/20160513134304708)
<item name="btnBgColor">#000000</item>
</style>
这里没什么不同的,就是在日间主题里Button 的文字颜色为黑色 背景为白色,而夜间模式则相反,其他都是一样,主要为了颜色效果,至于其他的属性,以及继承的主题完全可以自己定义即可。
此时在AndroidManifest.xml 文件里指定默认主题为 日间模式 如下:
修改主布局和MainActivity.java
activity_layout.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"
tools:context="me.jinkun.changetheme.MainActivity">
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/btnBgColor"
android:text="切换主题"
android:textColor="?attr/btnTxColor"/>
</RelativeLayout>
注意Button里的android:background=”?attr/btnBgColor” 和 android:textColor=”?attr/btnTxColor” 会引用我们在主题里设置的对应的btnBgColor和btnTxColor对应的值。
MainActivity.java代码如下:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 用sp来获取当前是显示的哪个主题
final SharedPreferences sp = getSharedPreferences("config", Context.MODE_PRIVATE);
final int theme = sp.getInt("theme", 0);
if (theme == 0) {
setTheme(R.style.AppTheme_Light);
} else {
setTheme(R.style.AppTheme_Night);
}
setContentView(R.layout.activity_main);
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//用sp来保存当前是显示的哪个主题
sp.edit().putInt("theme", theme == 0 ? 1 : 0).commit();
recreate();
}
});
}
}
这里切换主题后调用recreate()方法来重启Activity来实现主题的切换,非常简单,下面我们来看看效果,如下:
这里可以看的Button的颜色发生了改变,说明切换主题成功,这里也暴露一个非常致命的缺点就是重建Activity正规页面会闪一下,体验是相当不好的,当然也有解决办法,请参考开头提到的三种方式中其他方式,这里就不说了。如果你的Activity的生命周期做了很多其他操作,那么重启Activity就会带来很多麻烦,谨慎使用。如果你的应用可以容许有这样的体验,那就可以尝试一下了。
抽取BaseActivity
BaseActivity.java
public class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (MyApp.getInstance().getGlobleTheme() == MyApp.THEME_LIGHT) {
setTheme(R.style.AppTheme_Light);
} else {
setTheme(R.style.AppTheme_Night);
}
}
}
这个里面只是判断当前主题是日间还是夜间模式,然后选择显示什么主题,下面看下MyApp的实现。
MyApp.java
public class MyApp extends Application {
public static final int THEME_NIGHT = 0;
public static final int THEME_LIGHT = 1;
private static MyApp _instance;
@Override
public void onCreate() {
super.onCreate();
_instance = this;
}
public static MyApp getInstance() {
return _instance;
}
public SharedPreferences getGlobleSp() {
return getSharedPreferences("config", Context.MODE_PRIVATE);
}
public int getGlobleTheme() {
return getGlobleSp().getInt("theme", THEME_NIGHT);
}
public void changeGlobleTheme() {
getGlobleSp().edit().putInt("theme", getGlobleTheme() == THEME_LIGHT ? THEME_NIGHT : THEME_LIGHT).commit();
}
}
这里用SharePerferences来保存选择的主题。
AndroidManifest.xml 配置MyApp
<application
android:name=".MyApp"
配置MyApp即可。
遇到的一个坑
当我们不在MainActivity里切换主题,而是SettingActivity里切换主题,再回到MainActivity会发现MainActivity根本不会变,这是因为主题的设置是在onCreate里进行的,这就导致,一些已经启动的Activity无法切换主题,如下:
这个效果可以很明显的看出BUG来,
- 当我在MainActivity里切换主题很正常
- 当我在SettingActivity里切换主题再回到MainActivity里发现主题没变
这里暂时只有一个MainActivity没有变,要是存在其他的过时的Activity也会存在这种办法。
解决
当我在SettingActivity里切换主题的时候,重新启动MainActivity,并把MainActivity的启动模式设置为SingleTask,并且还清空说有的其他在后台的Activity如下:
设置MainActivity的启动模式:
SettingActivity.java里的切换主题的点击事件如下:
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//用sp来保存当前是显示的哪个主题
MyApp.getInstance().changeGlobleTheme();
finish();
Intent intent = new Intent(SettingActivity.this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | IntentCompat.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
overridePendingTransition(0, 0);
}
});
效果如下:
总结:
使用这种方式,非常简单就可以实现主题切换,但是页面闪烁体验不好,当然可以也可以尝试自定义布局,然后替换布局,以及只修改指定的View的样式等方式,自己看需求喽。
参考:
http://www.cnblogs.com/likeandroid/p/4501758.html
http://www.jianshu.com/p/2164fa5803b9