最近的项目一直是按照PRD与高清,修改系统设置,调整布局、间距、颜色,涉及到一些流程的更改与自定义控件,以及对settings源码结构的研究。在项目相对空闲是,做个整理记录。由于项目依赖系统源码环境,而且在赶项目的时候,只能以最快的速度解决当前的问题,而下面的设计的代码与效果图,都是个人封装的DEMO测试,毕竟不能仅仅只是最求项目的解决过关,学过用过,就应该做点总结,毕竟我觉得很多东西,在赶项目的时候是无法去过多的仔细研究,所以有居多“废代码”,很多地方是值得仔细研究与优化改进的。
首先对原生Settings的布局,及切换跳转,按照我的研究理解,做个流程的分析简介,后面会给出我的改进与实现
1.先从布局简单的说起:
在PreferenceActivity中 可以看到:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(com.android.internal.R.layout.preference_list_content);
2.右边ListView的显示。
代码详见内部类:HeaderAdapter。
//类型一,分类title,无焦点,不可点击
static final int HEADER_TYPE_CATEGORY= 0;
//类型二,正常的可点击的header项
static final int HEADER_TYPE_NORMAL = 1;
//带 switch 开关的header项
static final int HEADER_TYPE_SWITCH = 2;
case HEADER_TYPE_CATEGORY://下划线样式的TextView
view = new TextView(getContext(), null,android.R.attr.listSeparatorTextViewStyle);
case HEADER_TYPE_SWITCH://含有switch 控件的布局
view = mInflater.inflate(R.layout.preference_header_switch_item, parent,false);
case HEADER_TYPE_NORMAL:
view = mInflater.inflate(R.layout.preference_header_item, parent, false);
getMetaData-->onBuildHeaders-->onGetInitialHeader-->super.switchToHeader-->highlightHeader
1.onCreat 方法:
//...省略部分
getMetaData();
mInLocalHeaderSwitch = true;
super.onCreate(savedInstanceState);
mInLocalHeaderSwitch = false;
highlightHeader(mTopLevelHeaderId);
//... 省略部分
主要作用是获取当前Activity的 meta信息,参看manifest的定义,如这个是wifi设置界面的Activity信息描述
定义了,跳转进来的action,已经这个它要展示的信息,左边Header的 id(mTopLevelHeaderId),右边显示的fragment 类(mFragmentClass)。
下面是读取该信息。
private void getMetaData() {
try {
//获取当前Activity的Meta 信息
ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
PackageManager.GET_META_DATA);
if (ai == null || ai.metaData == null) return;
//ListView 中要选中的Header的Id 如R.id.wifi_settings
mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
//对应的切换 右边显示的Fragment
mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
// Check if it has a parent specified and create a Header object
//这个 应该是针对 single panel 检查它是否有上一级。
final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);
String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
if (parentFragmentClass != null) {
mParentHeader = new Header();
mParentHeader.fragment = parentFragmentClass;
if (parentHeaderTitleRes != 0) {
mParentHeader.title = getResources().getString(parentHeaderTitleRes);
}
}
} catch (NameNotFoundException nnfe) {
// No recovery
}
}
PreferenceActivity 源码 onCreat 方法主要 调用如下,
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//布局
setContentView(com.android.internal.R.layout.preference_list_content);
//...省略部分代码
if (initialFragment != null && mSinglePane) {
//单屏
} else {
onBuildHeaders(mHeaders);
if (mHeaders.size() > 0) {
if (!mSinglePane) {
if (initialFragment == null) {
Header h = onGetInitialHeader();
switchToHeader(h);
} else {
switchToHeader(initialFragment, initialArguments);
}
}
}
}
4.Settings 类对 onBuildHeaders的重写:
@Override
public void onBuildHeaders(List headers) {
//Header 资源
loadHeadersFromResource(R.xml.settings_headers, headers);
//根据相应条件,移除掉部分header,筛选出mFirstHeader
//第一个不为HEADER_TYPE_CATEGORY(不能获得触摸焦点) 分类项的Header,作为备用显示
//并记录 header id 对应ListView中的 index
updateHeaderList(headers);
}
@Override
public Header onGetInitialHeader() {
//获取 要显示的fragment
String fragmentClass = getStartingFragmentClass(super.getIntent());
//构造 header 对象
if (fragmentClass != null) {
Header header = new Header();
header.fragment = fragmentClass;
header.title = getTitle();
header.fragmentArguments = getIntent().getExtras();
mCurrentHeader = header;
return header;
}
//如果meta中没有,intent中也没有,返回updateHeaderList 中选出来的header
return mFirstHeader;
}
protected String getStartingFragmentClass(Intent intent) {
//如果前面 getMeta 中的读取到的mFragmentClass 不为空,直接return
if (mFragmentClass != null) return mFragmentClass;
//获取intent 中指定要 跳转到的类名
String intentClass = intent.getComponent().getClassName();
//就是当前activity ,不做处理
if (intentClass.equals(getClass().getName())) return null;
if ("com.android.settings.ManageApplications".equals(intentClass)
|| "com.android.settings.RunningServices".equals(intentClass)
|| "com.android.settings.applications.StorageUse".equals(intentClass)) {
// Old names of manage apps.
intentClass = com.android.settings.applications.ManageApplications.class.getName();
}
return intentClass;
}
6.PreferenceActivity 的onCreate中 switchToHeader ,就显示 了指定的fragment和 高亮指定的header项。
7.Settings 的onCreate中 ,更新左边的选中项,mTopLevelHeaderId 也是从getMetaData 中读出来的。因为在PreferenceActivity 的switchToHeader 中,如果ListView没有找到Header,就不会有高亮的选中项。
highlightHeader(mTopLevelHeaderId);