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文字为黑色 -->![这里写图片描述](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

代码地址:
https://github.com/cskun/ChangeTheme.git

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值