Android中主题切换简单实践

切换主题常见大概有三种方式,我这里用最简单的一种来实践。如下:

使用重启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文字为黑色 -->![这里写图片描述](http://img.blog.csdn.net/20160513134304708)
    <item name="btnBgColor">#000000</item>
</style>

这里没什么不同的,就是在日间主题里Button 的文字颜色为黑色 背景为白色,而夜间模式则相反,其他都是一样,主要为了颜色效果,至于其他的属性,以及继承的主题完全可以自己定义即可。

修改主布局和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的样式等方式,自己看需求喽。

代码可以到Linux公社资源站下载:

------------------------------------------分割线------------------------------------------

具体下载目录在 /2017年资料/5月/12日/Android中主题切换简单实践/

------------------------------------------分割线------------------------------------------

猜你喜欢

转载自www.linuxidc.com/Linux/2017-05/143695.htm