前言
随着软件的开发,用户的需求也变得多样丰富,在最近的一条反馈里,我注意到了有个需要用户自己设置主题的需求,于是这段时间我就在研究主题的实现。
结果是,复杂的主题变动许多都是在绘制上改动的,这样可以不重启activity,但是代码侵入性很强,而且以我现在的技术也没办法实现。因此,我们采用了另一种方法,利用activty快速重启的方式,在基类的create中完成主题的设置。
实现
用户设置界面
我们在这里为用户提供一个可选的设置列表
如上图,这样用户就可以选择我们提供的主题了。
这里的代码比较简单,就不单独放出来了,我们看看接下来这块。
实现考虑
设想一下,我们切换壁纸后,需要重启当前的活动,还需要重启已经打开了的活动,这样,我们就得考虑在基类管理所有的activity,接到事件后重启并且恢复所有的活动。这样比较麻烦,我们换一种想法。
让每个activity都注册一个广播,当收到广播后,就结束这个活动。当活动重启时,先判断用户选择了什么主题,再进行设置。这样我们就可以很方便的实现这个主题切换了,只是这样的实现有一些痛点。
利用广播通知
我们上面既然已经想好了怎么实现,就开始动手试一试吧。
让我们先在基类定义一个重启当前的活动的函数,如下面所写的。
open fun updateTheme() { //重启activity() recreate() }
接下来,让我们实现一个广播,这里就叫ThemeChangedBroadcast,让它继承掉BroadcastReceiver。
class ThemeChangedBroadcast : BroadcastReceiver() { /** * 这里主要是监听主题改变的,转发通知 * @param context Context * @param intent Intent */ override fun onReceive(context: Context, intent: Intent) { (context as AbsActivity).updateTheme() } }
这里我们把context转换为了AbsActivity,啊哈,想必你已经知道,要用动态注册广播的方式了。这样我们就可以利用context实现重启当前的activity。
至此,当这里接收到广播后就会调用这个updateTheme函数,重启activity。
广播动态注册
我们得让每个活动都注册这个广播,因此我们还是在基类覆写下面的函数。
override fun onResume() { super.onResume() //注册广播 registerReceiver( //这块是主题广播 mThemeChangedBroadcast, IntentFilter("com.imcys.bilibilias.app.THEME_CHANGED") ) } override fun onDestroy() { super.onDestroy() //取消注册(防止泄露) unregisterReceiver(mThemeChangedBroadcast) // 移除当前活动 removeActivity(this) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setTheme() }
当启动时注册活动,关闭时取消注册,防止泄露,而这条广播的com.imcys.bilibilias.app.THEME_CHANGED。
而我们在onCreate中调用了另一个函数。
//检查主题 private fun setTheme() { val theme = PreferenceManager.getDefaultSharedPreferences(this).run { getString("app_theme", "System") } when (theme) { "System" -> { AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) } "Light" -> { AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) } "Dark" -> { AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) } "Pink" -> { this.setTheme(R.style.Theme_BILIBILIAS) } } }
通过此方法我们可以设置暗夜模式或者亮色模式,以及其他的颜色,由此,我们的主题修改就大功告成了。
文末
此方法虽然解决了动态主题修改的问题,但是仍然存在一些不合理性,我们知道有许多的APP切换主题是不会重启活动的,也就是不会卡一下,更多的办法需要继续探索。以后有机会继续说。
发表回复