在这里我们所说的并非自定义属性,关于自定义属性,请参考之前的文章,讲的很细,今天所说的是自定义“属性名”。
先讲一下,为什么我们需要自定义我们的属性名,加入你再开发一个应用,该应用你设置好几种主题,每一个主题对应与整个程序的很多中属性,假如在一种主题当中有内容背景色(属性为:background),而且还有字体背景色(同样为:background),如果我需要更换主题的时候,以上所说的颜色的改变就会略有麻烦,如果此时,我给以上颜色的取值取了名字。比如第一个颜色我可以设置为"contentBackgrounp",第二个颜色就可以设置为"fontBackgrounp",这样的话呢,我就可以区分这两种 颜色,更换主题时,只需调用setTheme()方法就可以了,其他的什么都不需要改变。
上面说的有些不太懂,没有办法,语言水平就到这了,下面我用代码去实现这些。
首先,我需要定义以上两种属性:theme_atrrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="contentBackgrounp" format="reference"></attr>
<attr name="fontBackgrounp" format="reference"></attr>
</resources>
NOTICE:以上属性的格式一定要为reference格式,因为虽然我们设置了以上属性,但是我们不关心它是什么,我们关心的是它指向哪里,也就说这个属性实际上就代表着它所指向的值。(这个意思下面我再细说)
下面,我就要对以上属性,在我所使用的主题中进行赋值theme.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--夜间模式下的主题-->
<style name="AppBaseTheme_Dark" parent="@style/Theme.AppCompat.Light">
<item name="contentBackgrounp">@color/dark_content</item>
<item name="fontBackgrounp">@color/dark_font</item>
</style>
<!--日间模式下的主题-->
<style name="AppBaseTheme_Light" parent="@style/Theme.AppCompat.Light">
<item name="contentBackgrounp">@color/day_content</item>
<item name="fontBackgrounp">@color/day_font</item>
</style>
</resources>
下面,我们就要AndroidMainfest.xml文件中初始化我们的主题,此处假如我们默认为日间模式
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppBaseTheme_Light" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
也就是说设置如下语句,如果不设置如下语句,程序会报错
android:theme="@style/AppBaseTheme_Light"
然后,我们就可以在我们的布局中去使用我们定义好的属性:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="?attr/contentBackgrounp">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/fontBackgrounp"/>
</RelativeLayout>
因为,我们在使用过程中这两个组件的background都是一个指向的值,它的真正值是我们在theme.xml中设置的,所以,如果要改变主题,其他的什么都不需要改变,如果要设置为夜间模式,只需调用方法setTheme(R.style.AppBasetheme_Dark)即可。
由于setTheme方法的调用必须在调用执行方法setContentView()之前:使用,在使用时有两种处理方法;
第一种,也是最简单的方法:
setTheme(R.style.AppTheme_Light);
this.onCreate(new Bundle());
setTheme(R.style.AppTheme_Light);
this.onCreate(new Bundle());
只需以上两句就可以达到更换主题的方法。
第二种方法,虽然代码长度略长,但是是比较好的设计方法:
在SharedPreferences中配置一个键,存储主题模式,使用过程如下:
boolean isNight = false;
SharedPreferences sp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sp = PreferenceManager.getDefaultSharedPreferences(this);
setTheme((isNight = sp.getBoolean("isNight", false)) ? R.style.AppTheme_Dark :
R.style.AppTheme_Light);
setContentView(R.layout.activity_main);
boolean isNight = false;
SharedPreferences sp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sp = PreferenceManager.getDefaultSharedPreferences(this);
setTheme((isNight = sp.getBoolean("isNight", false)) ? R.style.AppTheme_Dark :
R.style.AppTheme_Light);
setContentView(R.layout.activity_main);
点击按钮:
@Override
public void onClick(View v) {
int resId = v.getId();
switch (resId) {
case R.id.day:
if(isNight) {
SharedPreferences.Editor editor = sp.edit();
editor.putBoolean("isNight",false);
recreate();
}
break;
case R.id.dark:
if(!isNight) {
SharedPreferences.Editor editor = sp.edit();
editor.putBoolean("isNight", true);
recreate();
}
break;
}
@Override
public void onClick(View v) {
int resId = v.getId();
switch (resId) {
case R.id.day:
if(isNight) {
SharedPreferences.Editor editor = sp.edit();
editor.putBoolean("isNight",false);
recreate();
}
break;
case R.id.dark:
if(!isNight) {
SharedPreferences.Editor editor = sp.edit();
editor.putBoolean("isNight", true);
recreate();
}
break;
}
关于方法recreate:
Cause this Activity to be recreated with a new instance. This results
in essentially the same flow as when the Activity is created due to
a configuration change -- the current instance will go through its
lifecycle to onDestroy() and a new instance then created after it.
Cause this Activity to be recreated with a new instance. This results
in essentially the same flow as when the Activity is created due to
a configuration change -- the current instance will go through its
lifecycle to onDestroy() and a new instance then created after it.
意思是说:调用该方法,会使得该Activity重建一个新的实例,当前的实例会调用生命周期的onDestroy方法,并且在调用onDestroy方法之后用重新创建一个新的实例