转载请注明出处:http://blog.csdn.net/htwhtw123/article/details/79166947
在开发Android应用设置的界面时,往往会使用Android的Preference API,例如PreferenceCategory,CheckBoxPreference,EditTextPreference,ListPreference,SwitchPreference,他们不仅有设置界面所需要的UI,还有自动存储选择的功能。接下来将总结他们的使用方法。
#1.概览
与View及其子类将对应的布局文件放在res/layout文件夹下不同, Preference 类的各种子类构建的布局文件放在res/xml文件夹下。由于应用的设置 UI 是使用 Preference 对象(而非 View 对象)构建而成,因此需要使用专门的 Activity 或 Fragment 子类显示列表设置( PreferenceFragment或PreferenceActivity )。
Preference 对象是单个设置的构建基块。每个 Preference 均作为项目显示在列表中,并提供适当的 UI 供用户修改设置。
常用的preference API及其作用:
PreferenceCategory 用于存放Preference对象,将对象分组
CheckBoxPreference 可创建一个列表项用于显示复选框,
EditTextPreference 打开一个包含 EditText 小部件的对话框
SwitchPreference 可供选择的switchButton
ListPreference 可创建一个项目用于打开包含选择列表的对话框。
在 PreferenceFragment或PreferenceActivity中使用preference API,官方建议:在开发针对 Android 3.0 及 更高版本的应用,使用 PreferenceFragment。而在使用AndroidStudio3.0.1中使用PreferenceActivity的话,它的必要的方法也会有警告
,且两者用法相似,所以这里只介绍在PreferenceFragment中使用preference对象。
每个 Preference 都有一个相应的键值对,可供系统用来将设置保存在应用设置的默认 SharedPreferences 文件中。当用户更改设置时,系统会更新 SharedPreferences 文件中的相应值。应在需要读取值以根据用户设置确定应用的行为时,才与关联的 SharedPreferences 文件直接交互。保存的SharedPreferences 文件名是:包名+下划线+preferences。
建议在Fragment或Activity中的Create()中调用以下方法,以初始化用户以前设置的值,到对应的preference对象。
PreferenceManager.setDefaultValues(this,
R.xml.advanced_preferences, false);
#2.共有使用方法
preference 对象共有属性:
android:key
对于要保留数据值的首选项,必须拥有此属性。它指定系统在将此设置的值保存在 SharedPreferences 中时所用的唯一键(字符串)。
不需要此属性的唯一情形是:首选项是 PreferenceCategory 或PreferenceScreen,或者首选项指定要调用的 Intent(使用 元素)或要显示的 Fragment(使用 android:fragment 属性)。
android:title
此属性为设置提供用户可见的名称。
android:defaultValue
此属性指定系统应该在 SharedPreferences 文件中设置的初始值。您应该为所有设置提供默认值。
一个布局文件的例子,它位于res/xml文件夹下:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="PreferenceCategory1">
<CheckBoxPreference
android:key="checkbox_preference"
android:summary="summary_checkbox_preference"
android:title="title_checkbox_preference"/>
</PreferenceCategory>
</PreferenceScreen>
xml文件的根标签需要是PreferenceScreen,PreferenceCategory为preference分组,效果如下。
第一行子是PreferenceCategory的title属性定义,第二行由CheckBoxPreference的title属性定义,第三行是CheckBoxPreference的summary属性。
在PreferenceFragment中加载的布局文件preferences
public class SettingsFragment extends PreferenceFragment{
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
}
与view对象使用id不同,preference对象使用key标识控件,获取preference对象,并且通过对象的set/get方法,分别获得和改变key、summary、title等属性。checkbox_preference是在xml文件中定义的CheckBoxPreference 的key属性:
CheckBoxPreference checkBoxPreference = (CheckBoxPreference)
findPreference("checkbox_preference");
可以使用onPreferenceClickListener监听点击事件,但是一般关心的都是用户进行操作并保存更改的事件监听。所以这里讲一下onPreferenceChange:
checkBoxPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean ·(Preference preference, Object newValue) {
//获取preference被改变的新值
Toast.makeText(getActivity(), newValue.toString(), Toast.LENGTH_SHORT).show();
return true;
}
});
其中参数:preference是已经发生改变的preference对象,newValue是preference对象的新value。return true,使事件被消费掉,控件ui才会随用户操作改变,更改才会被保存。
#3.使用的效果及其注意
##CheckBoxPreference
CheckBoxPreference存储的数据类型是boolean型,它没有什么特有的属性,在onPreferenceChange方法的newValue是Boolean型。
##EditTextPreference
可以在xml文件中设置defaultValue属性设置EditTextPreference对话框的默认值,dialogTitle设置对话框的标题。可在前面讲的onPreferenceChange方法的newValue参数处获取改变值。
也可以使用editTextPreference.getEditText().getText().toString();在获取在对话框中的输入值
##ListPreference
使用ListPreference的布局文件中的以下属性:
dialogTitle:定义对话框的标题
entries:定义展示的item的string资源
entryValues:定义每个entries中定义的item的对应的值
下面一个例子,实现以上效果:
添加以下文件res/values/arrays.xml,其中存放对话框显示数据:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="entries_list_preference">
<item >list1</item>
<item >list2</item>
<item >list3</item>
</string-array>
<string-array name="entry_values_list_preference">
<item >defaultValue1</item>
<item >defaultValue2</item>
<item >defaultValue3</item>
</string-array>
</resources>
在MyPreferenceFragemnt.java有如下代码段:
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preference);
...
listPreference = (ListPreference) findPreference("list_preference");
editTextPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
//可以这样获取新值
// Toast.makeText(getActivity(), newValue.toString()+"", Toast.LENGTH_SHORT).show();
String t = editTextPreference.getEditText().getText().toString();
Toast.makeText(getActivity(), t+"", Toast.LENGTH_SHORT).show();
return true;
}
});
}
在布局文件res/xml/preferences.xml中加入以下代码:
...
<ListPreference
android:dialogTitle="dialog_title_list_preference"
android:entries="@array/entries_list_preference"
android:entryValues="@array/entry_values_list_preference"
android:key="list_preference"
android:summary="summary_list_preference"
android:title="title_list_preference"/>
...
最后,将碎片加载到Activity。这里略过,如果不知道如何使用碎片,那么请看郭大神的讲解: Android Fragment完全解析,关于碎片你所需知道的一切
##SwitchPreference
这是有title属性,没有summary属性的SwitchPreference
使用方法同CheckBoxPreference.
#4.使用SharePreference直接获取存储值
前面讲过,这些preference对象在用户操作后会存储相应的数据。其实是以SharePreference存储的,SharePreference文件名称会是:包名+下划线+preferences,而键值对的key就是preference的key.。以下示例,取获取checkBoxPreference的存储的值。
SharedPreferences sharedPreferences = context.getSharedPreferences(getActivity().getPackageName() + "_preferences", Context.MODE_PRIVATE);
String result=sharedPreferences.getBoolean("checkbox_preference", false);
这样在不是设置界面也能知道用户设置的值
#5.使用 Intent
可以通过在xml文件中设置首选项的intent属性,来打开不同的 Activity(而不是网络浏览器等设置屏幕)或查看网页。 要在用户选择首选项时调用 Intent,将 元素添加为相应 Preference元素的子元素即可。
<Preference android:title="prefs_web_page" >
<intent android:action="android.intent.action.VIEW"
android:data="http://www.example.com" />
</Preference>
这里可以使用显示或隐式intent,直接使用Preference,默认将不会有线在下方与其他元素分割。
#6.依赖型选项(可隐藏选项)
只有选定之前的某个首选项后,这个选项才可选。效果如下,从效果图中不难这种用法看出一些特征。
只需要在xml文件下,加入属性 android:dependency=“”“所依赖的preference对象的key属性值”。以下例子可实现以上效果:
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="preference_attributes">
<CheckBoxPreference
android:key="parent_checkbox_preference"
android:summary="summary_parent_preference"
android:title="title_parent_preference"/>
<CheckBoxPreference
android:dependency="parent_checkbox_preference"
android:key="child_checkbox_preference"
android:layout="?android:attr/preferenceLayoutChild"
android:summary="summary_child_preference"
android:title="title_child_preference"/>
</PreferenceCategory>
</PreferenceScreen>
#7.加载自定义的layout并监听内部控件点击事件
在xml文件中preference对象的属性加上属性:android:layout="@layout/my_layout",比如一个完全空的preference展现一个自定义的my_layout.xml:
<Preference
android:layout="@layout/my_layout">
</Preference>
监听点击事件的两种方式
1.android:onClick=""
可以监听自定义layout控件点击事件的方法是在layout布局文件中给想监听的控件添加一个android:onClick=""属性,如:
<TextView
...
android:onClick="myClick"
.../>
然后在Activity中监听点击:
public void myClick(View v) {
}
2.重写preference 的onBindView()方法
自定义一个类继承preference控件,重写其中的onBindView(view)方法,它的参数view就是将要加载的视图的根View,用view.findviewById(int)即可获得自定义的布局中的控件的id,自然可以设置监听事件。注意,preference的xml文件中,应以带包名全名的形式使用这个自己实现的类。下面一个例子:
public class MySwitchPrefernce extends SwitchPreference {
@Override
protected void onBindView(View view) {
super.onBindView(view);
view.findViewById(R.id.withText).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
}
public MySwitchPrefernce(Context context, AttributeSet attrs, int defStyleAttr, int
defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
}
#8.完整的demo代码:
preference布局文件:res/xml/preference.xml:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="PreferenceCategory1">
<CheckBoxPreference
android:key="checkbox_preference"
android:summary="summary_checkbox_preference"
android:title="title_checkbox_preference"/>
</PreferenceCategory>
<PreferenceCategory
android:title="PreferenceCategory2">
<EditTextPreference
android:dialogTitle="dialog_title_edit_text_preference"
android:key="edit_text_preference"
android:summary="summary_edit_text_preference"
android:title="title_edit_text_preference"/>
<ListPreference
android:dialogTitle="dialog_title_list_preference"
android:entries="@array/entries_list_preference"
android:entryValues="@array/entry_values_list_preference"
android:key="list_preference"
android:summary="summary_list_preference"
android:title="title_list_preference"/>
</PreferenceCategory>
<PreferenceCategory>
<SwitchPreference
android:title="SwitchPreference"
android:defaultValue="true"
android:key="switch_preference"
/>
<Preference android:title="intent_web_page" >
<intent android:action="android.intent.action.VIEW"
android:data="https://www.baidu.com" />
</Preference>
</PreferenceCategory>
<PreferenceCategory
android:title="preference_attributes">
<CheckBoxPreference
android:key="parent_checkbox_preference"
android:summary="summary_parent_preference"
android:title="title_parent_preference"/>
<CheckBoxPreference
android:dependency="parent_checkbox_preference"
android:key="child_checkbox_preference"
android:layout="?android:attr/preferenceLayoutChild"
android:summary="summary_child_preference"
android:title="title_child_preference"/>
<Preference
android:layout="@layout/my_layout">
</Preference>
</PreferenceCategory>
</PreferenceScreen>
碎片MyPreferenceFragment.java代码:
package com.example.test.preference;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.preference.SwitchPreference;
import android.support.annotation.Nullable;
import android.util.Log;
import android.widget.Toast;
import com.example.test.R;
public class MyPreferenceFragment extends PreferenceFragment {
private static final String TAG = "MyPreferenceFragment";
ListPreference listPreference;
CheckBoxPreference checkBoxPreference;
EditTextPreference editTextPreference;
SwitchPreference switchPreference;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preference);
init();
}
private void init() {
listPreference = (ListPreference) findPreference("list_preference");
checkBoxPreference = (CheckBoxPreference) findPreference("checkbox_preference");
editTextPreference = (EditTextPreference) findPreference("edit_text_preference");
switchPreference = (SwitchPreference) findPreference("switch_preference");
listPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
Toast.makeText(getActivity(), newValue.toString()+"", Toast.LENGTH_SHORT).show();
return true;//这里返回true点击效果才会生效
}
});
checkBoxPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
//获取存储文件存储的信息
Toast.makeText(getActivity(), newValue.toString(), Toast.LENGTH_SHORT).show();
String summary = preference.getSummary().toString();
Log.d(TAG, "onPreferenceChange: "+summary);
//直接访问存储文件:
// SharedPreferences sharedPreferences = getActivity().getSharedPreferences(getActivity().getPackageName() + "_preferences", Context.MODE_PRIVATE);
// Toast.makeText(getActivity(), sharedPreferences.getBoolean("checkbox_preference", false) + "", Toast.LENGTH_SHORT).show();
return true;
}
});
editTextPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
// Toast.makeText(getActivity(), newValue.toString()+"", Toast.LENGTH_SHORT).show();
String t = editTextPreference.getEditText().getText().toString();
Toast.makeText(getActivity(), t+"", Toast.LENGTH_SHORT).show();
return true;
}
});
switchPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
Log.d(TAG, "onPreferenceChange: "+newValue.toString());
Toast.makeText(getActivity(), newValue.toString()+"", Toast.LENGTH_SHORT).show();
return true;
}
});
}
}
加载碎片的活动:MyPreferenceActivity.java
package com.example.test.preference;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.example.test.R;
public class MyPreferenceActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_preference);
FragmentTransaction transaction=getFragmentManager().beginTransaction();
transaction.replace(R.id.fragment, new MyPreferenceFragment());
transaction.commit();
}
//自定义layout中textView点击监听
public void myClick(View v) {
Toast.makeText(this, ((TextView)v).getText()+"", Toast.LENGTH_SHORT).show();
}
}
活动MyPreferenceActivity的布局文件res/layout/activity_my_preference.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.test.preference.MyPreferenceActivity">
<FrameLayout
android:id="@+id/fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"></FrameLayout>
</LinearLayout>
让preference对象加载的自定义布局layout布局文件:res/layout/my_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:text="啦啦"
android:onClick="myClick"
android:textSize="30sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.constraint.ConstraintLayout>