虽然PreferenceActivity的UI比较搓,但是由于其良好的封装性和实用性,所以在一些场景还是有一定的使用价值。所以如何能优化它的UI让它和你程序相配就十分必要了。毕竟对于程序员来说能懒点就懒点,哈哈。
首先,
public abstract class PreferenceActivity extends ListActivity implements PreferenceManager.OnPreferenceTreeClickListener, PreferenceFragment.OnPreferenceStartFragmentCallback
这就表明可以替换背景,可以替换Divider,Selector。
它的adapter是PreferenceGroupAdapter,见于PreferenceScreen:
public void bind(ListView listView) { listView.setOnItemClickListener(this); listView.setAdapter(getRootAdapter()); onAttachedToActivity(); }
这个方法在PreferenceActivity里被掉,用于加载adapter。
package android.preference; import java.util.ArrayList; import java.util.Collections; import java.util.List; import android.os.Handler; import android.preference.Preference.OnPreferenceChangeInternalListener; import android.view.View; import android.view.ViewGroup; import android.widget.Adapter; import android.widget.BaseAdapter; import android.widget.ListView; /** * An adapter that returns the {@link Preference} contained in this group. * In most cases, this adapter should be the base class for any custom * adapters from {@link Preference#getAdapter()}. * <p> * This adapter obeys the * {@link Preference}'s adapter rule (the * {@link Adapter#getView(int, View, ViewGroup)} should be used instead of * {@link Preference#getView(ViewGroup)} if a {@link Preference} has an * adapter via {@link Preference#getAdapter()}). * <p> * This adapter also propagates data change/invalidated notifications upward. * <p> * This adapter does not include this {@link PreferenceGroup} in the returned * adapter, use {@link PreferenceCategoryAdapter} instead. * * @see PreferenceCategoryAdapter */ class PreferenceGroupAdapter extends BaseAdapter implements OnPreferenceChangeInternalListener { private static final String TAG = "PreferenceGroupAdapter"; /** * The group that we are providing data from. */ private PreferenceGroup mPreferenceGroup; /** * Maps a position into this adapter -> {@link Preference}. These * {@link Preference}s don't have to be direct children of this * {@link PreferenceGroup}, they can be grand children or younger) */ private List<Preference> mPreferenceList; /** * List of unique Preference and its subclasses' names. This is used to find * out how many types of views this adapter can return. Once the count is * returned, this cannot be modified (since the ListView only checks the * count once--when the adapter is being set). We will not recycle views for * Preference subclasses seen after the count has been returned. */ private ArrayList<PreferenceLayout> mPreferenceLayouts; private PreferenceLayout mTempPreferenceLayout = new PreferenceLayout(); /** * Blocks the mPreferenceClassNames from being changed anymore. */ private boolean mHasReturnedViewTypeCount = false; private volatile boolean mIsSyncing = false; private Handler mHandler = new Handler(); private Runnable mSyncRunnable = new Runnable() { public void run() { syncMyPreferences(); } }; private static class PreferenceLayout implements Comparable<PreferenceLayout> { private int resId; private int widgetResId; private String name; public int compareTo(PreferenceLayout other) { int compareNames = name.compareTo(other.name); if (compareNames == 0) { if (resId == other.resId) { if (widgetResId == other.widgetResId) { return 0; } else { return widgetResId - other.widgetResId; } } else { return resId - other.resId; } } else { return compareNames; } } } public PreferenceGroupAdapter(PreferenceGroup preferenceGroup) { mPreferenceGroup = preferenceGroup; // If this group gets or loses any children, let us know mPreferenceGroup.setOnPreferenceChangeInternalListener(this); mPreferenceList = new ArrayList<Preference>(); mPreferenceLayouts = new ArrayList<PreferenceLayout>(); syncMyPreferences(); } private void syncMyPreferences() { synchronized(this) { if (mIsSyncing) { return; } mIsSyncing = true; } List<Preference> newPreferenceList = new ArrayList<Preference>(mPreferenceList.size()); flattenPreferenceGroup(newPreferenceList, mPreferenceGroup); mPreferenceList = newPreferenceList; notifyDataSetChanged(); synchronized(this) { mIsSyncing = false; notifyAll(); } } private void flattenPreferenceGroup(List<Preference> preferences, PreferenceGroup group) { // TODO: shouldn't always? group.sortPreferences(); final int groupSize = group.getPreferenceCount(); for (int i = 0; i < groupSize; i++) { final Preference preference = group.getPreference(i); preferences.add(preference); if (!mHasReturnedViewTypeCount && !preference.hasSpecifiedLayout()) { addPreferenceClassName(preference); } if (preference instanceof PreferenceGroup) { final PreferenceGroup preferenceAsGroup = (PreferenceGroup) preference; if (preferenceAsGroup.isOnSameScreenAsChildren()) { flattenPreferenceGroup(preferences, preferenceAsGroup); } } preference.setOnPreferenceChangeInternalListener(this); } } /** * Creates a string that includes the preference name, layout id and widget layout id. * If a particular preference type uses 2 different resources, they will be treated as * different view types. */ private PreferenceLayout createPreferenceLayout(Preference preference, PreferenceLayout in) { PreferenceLayout pl = in != null? in : new PreferenceLayout(); pl.name = preference.getClass().getName(); pl.resId = preference.getLayoutResource(); pl.widgetResId = preference.getWidgetLayoutResource(); return pl; } private void addPreferenceClassName(Preference preference) { final PreferenceLayout pl = createPreferenceLayout(preference, null); int insertPos = Collections.binarySearch(mPreferenceLayouts, pl); // Only insert if it doesn't exist (when it is negative). if (insertPos < 0) { // Convert to insert index insertPos = insertPos * -1 - 1; mPreferenceLayouts.add(insertPos, pl); } } public int getCount() { return mPreferenceList.size(); } public Preference getItem(int position) { if (position < 0 || position >= getCount()) return null; return mPreferenceList.get(position); } public long getItemId(int position) { if (position < 0 || position >= getCount()) return ListView.INVALID_ROW_ID; return this.getItem(position).getId(); } public View getView(int position, View convertView, ViewGroup parent) { final Preference preference = this.getItem(position); // Build a PreferenceLayout to compare with known ones that are cacheable. mTempPreferenceLayout = createPreferenceLayout(preference, mTempPreferenceLayout); // If it's not one of the cached ones, set the convertView to null so that // the layout gets re-created by the Preference. if (Collections.binarySearch(mPreferenceLayouts, mTempPreferenceLayout) < 0) { convertView = null; } return preference.getView(convertView, parent); } @Override public boolean isEnabled(int position) { if (position < 0 || position >= getCount()) return true; return this.getItem(position).isSelectable(); } @Override public boolean areAllItemsEnabled() { // There should always be a preference group, and these groups are always // disabled return false; } public void onPreferenceChange(Preference preference) { notifyDataSetChanged(); } public void onPreferenceHierarchyChange(Preference preference) { mHandler.removeCallbacks(mSyncRunnable); mHandler.post(mSyncRunnable); } @Override public boolean hasStableIds() { return true; } @Override public int getItemViewType(int position) { if (!mHasReturnedViewTypeCount) { mHasReturnedViewTypeCount = true; } final Preference preference = this.getItem(position); if (preference.hasSpecifiedLayout()) { return IGNORE_ITEM_VIEW_TYPE; } mTempPreferenceLayout = createPreferenceLayout(preference, mTempPreferenceLayout); int viewType = Collections.binarySearch(mPreferenceLayouts, mTempPreferenceLayout); if (viewType < 0) { // This is a class that was seen after we returned the count, so // don't recycle it. return IGNORE_ITEM_VIEW_TYPE; } else { return viewType; } } @Override public int getViewTypeCount() { if (!mHasReturnedViewTypeCount) { mHasReturnedViewTypeCount = true; } return Math.max(1, mPreferenceLayouts.size()); } }
它的getView里掉的是Preference的getView。Preference类似于View,是所有相关UI类的基类。以下是和UI相关的重要代码。
public View getView(View convertView, ViewGroup parent) { if (convertView == null) { convertView = onCreateView(parent); } onBindView(convertView); return convertView; } protected View onCreateView(ViewGroup parent) { final LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); final View layout = layoutInflater.inflate(mLayoutResId, parent, false); final ViewGroup widgetFrame = (ViewGroup) layout .findViewById(com.android.internal.R.id.widget_frame); if (widgetFrame != null) { if (mWidgetLayoutResId != 0) { layoutInflater.inflate(mWidgetLayoutResId, widgetFrame); } else { widgetFrame.setVisibility(View.GONE); } } return layout; }
所以基本上每个Preference UI控件最多和mLayoutResId和mWidgetLayoutResId相关。
首先查找它们的布局,比如PreferenceCategory,attr为com.android.internal.R.attr.preferenceCategoryStyle,
对应主题中的style为<item name="preferenceCategoryStyle">@android:style/Preference.Category</item>。
<style name="Preference.Category"> <item name="android:layout">@android:layout/preference_category</item> <!-- The title should not dim if the category is disabled, instead only the preference children should dim. --> <item name="android:shouldDisableView">false</item> <item name="android:selectable">false</item> </style>
如下列出所有的attr: <declare-styleable name="Theme"> ...... <attr name="preferenceScreenStyle" format="reference"/> <!-- Default style for PreferenceCategory. --> <attr name="preferenceCategoryStyle" format="reference"/> <!-- Default style for Preference. --> <attr name="preferenceStyle" format="reference"/> <!-- Default style for informational Preference. --> <attr name="preferenceInformationStyle" format="reference"/> <!-- Default style for CheckBoxPreference. --> <attr name="checkBoxPreferenceStyle" format="reference"/> <!-- Default style for YesNoPreference. --> <attr name="yesNoPreferenceStyle" format="reference"/> <!-- Default style for DialogPreference. --> <attr name="dialogPreferenceStyle" format="reference"/> <!-- Default style for EditTextPreference. --> <attr name="editTextPreferenceStyle" format="reference"/> <!-- Default style for RingtonePreference. --> <attr name="ringtonePreferenceStyle" format="reference"/> <!-- The preference layout that has the child/tabbed effect. --> <attr name="preferenceLayoutChild" format="reference"/> </declare-styleable> 对应的style为: <style name="Theme"> ...... <!-- Preference styles --> <item name="preferenceScreenStyle">@android:style/Preference.PreferenceScreen</item> <item name="preferenceCategoryStyle">@android:style/Preference.Category</item> <item name="preferenceStyle">@android:style/Preference</item> <item name="preferenceInformationStyle">@android:style/Preference.Information</item> <item name="checkBoxPreferenceStyle">@android:style/Preference.CheckBoxPreference</item> <item name="yesNoPreferenceStyle">@android:style/Preference.DialogPreference.YesNoPreference</item> <item name="dialogPreferenceStyle">@android:style/Preference.DialogPreference</item> <item name="editTextPreferenceStyle">@android:style/Preference.DialogPreference.EditTextPreference</item> <item name="ringtonePreferenceStyle">@android:style/Preference.RingtonePreference</item> <item name="preferenceLayoutChild">@android:layout/preference_child</item> </style>
我没搞清楚的是这个style是在什么地方设进去的。所以如果要修改PreferenceCategory的UI,只需从系统源码中拷贝出这个布局XML,修改它的title的id:@+android:id/title为@android:id/title,同时
<PreferenceCategory
android:layout="@layout/preference_category"
android:title="你好1" >
由于PreferenceCategory是直接加载preference_category的,所以替换了默认的preference.xml,所以就算你配上android:widgetLayout也没用。
修改CheckBoxPreference的UI需要:layout->preference.xml widgetLayout->preference_widget_checkbox.xml,同时修改id。
拿到布局文件后,字体,字体大小,颜色等布局元素你想怎么弄就怎么弄了。
需要注意的是,如果你想要保存那写选中的数据,必须要对preference UI 控件设置key。因为保存XML时候必须要有key。
发表评论
-
ScrollView嵌套Edittext
2015-04-08 18:26 843scrollview 中加入多个控件如 edittext 后会 ... -
android 布局式跑马灯,非TextView
2015-04-07 10:51 494如题,简单的实现了跑马灯效果,把Scroll.java放入an ... -
Android圆角图片
2015-03-11 17:44 694my_wane_shape.xml 快速圆角背景边框实现, ... -
SQLite多线程读写实践及常见问题总结
2015-02-13 17:06 944基本操作的部分,大家都很熟悉了,这里根据个人切身经验,总结了一 ... -
android加速度感应
2015-01-19 10:25 14731.android测量数据 (1)android设备坐标系 ... -
MatrixCursor的使用
2015-01-19 09:49 1045ContentProvider对外共享数据的时候的query( ... -
Android 获取控件的宽高高级用法(MeasureSpec)
2015-01-15 14:23 998一个MeasureSpec封装了父 ... -
Android_GridView_GridView概述及实现水平滑动
2015-01-14 17:14 11511.GridView简介 GridView是ViewGroup ... -
Android MMS,SMS之常用Uri
2014-09-19 16:32 1323Android MMS,SMS之常用Uri Android ... -
android短彩信查询以及MMS表结构
2014-09-19 16:31 2236android短信的数据库的Uri是不公开的, 读取起来时灰常 ... -
使用Android自带DownloadManager下载文件
2014-08-19 11:04 767SDK在API Level 9中加入了DownloadMan ... -
android textview里链接点击事件,增加图片
2014-08-07 16:45 1146Android系统默认给TextView插入图片提供了三种方 ... -
android Home事件汇总
2014-07-18 11:30 1005方法一:android 4.0以后无法通过更改页面的类型来 ... -
Android风格与主题(style and theme)
2014-07-16 16:35 672Android xml风格和主题文 ... -
Android中播放声音的两种方法
2014-05-30 15:09 668在Android中,音频、视 ... -
android 杀进程方法
2014-05-26 17:43 1008关闭应用的方法: 1.System.exit(0); ... -
android service 生命周期
2014-04-21 16:16 787有了 Service 类我们如何启动他呢,有两种方法: ... -
解决ADB端口被占用的问题
2014-04-21 16:14 833究其源就是adb server没启动 经过分析整理如下: ... -
输入法隐藏打开
2013-12-23 14:24 817首次进入activity,如果有个edittex ... -
google经纬度互转
2013-07-11 16:34 935https://developers.google.com/ ...
相关推荐
这样,PreferenceActivity会解析XML文件,并自动在界面上生成对应的UI元素。 为了响应用户的操作,如点击事件,你可以重写onOptionsItemSelected(MenuItem item)方法,检查被选中的菜单项是否来自...
然而,标准的`PreferenceActivity`样式可能无法满足所有设计需求,因此开发者有时需要自定义`PreferenceActivity`来实现特定的UI效果。 自定义`PreferenceActivity`主要包括以下几个方面: 1. **布局文件定制**: ...
使用 PreferenceActivity设置个性信息, 参考:android 设置类PreferenceActivity http://blog.csdn.net/xiaobijia/article/details/41479235
PreferenceActivity用法简介 Android X
4. **更新UI**:当偏好设置发生变化时,可能需要更新相应的UI元素。这可以通过监听`SharedPreferences`的变化来实现,例如使用`SharedPreferences.OnSharedPreferenceChangeListener`。 5. **适配新版本**:由于`...
"仿IOS的PreferenceActivity界面"就是一个这样的实践,它主要涉及到Android的Preference类和Activity的使用,以及UI样式的美化。PreferenceActivity是Android系统提供的一种用于展示设置界面的特殊Activity,它能够...
Google推荐使用`PreferenceFragmentCompat`或`PreferenceFragment`来代替,它们可以在任何版本的Android上运行,并提供了更好的兼容性和更现代的UI设计。例如,使用`PreferenceFragmentCompat`的方式如下: ```java...
在Android应用开发中,PreferenceActivity是用于创建设置界面的一个特殊Activity。它允许开发者以XML方式定义用户界面元素,如开关、选择列表等,使得创建设置界面变得更加简洁和规范。本教程将深入探讨如何在...
8. **保存和恢复状态**: 如果需要在配置更改(如屏幕旋转)后保持设置状态,可以在`onSaveInstanceState`和`onRestoreInstanceState`方法中处理。 9. **测试和调试**: 完成以上步骤后,运行应用并测试设置界面的...
在实际开发中,我们可能会遇到需要自定义Preference的情况,比如需要添加额外的事件监听或者改变默认的UI行为。这时,我们可以创建一个继承自Preference的子类,并覆盖相应的方法。然后在XML中使用这个自定义的类名...
在Android开发中,PreferenceActivity是用于创建设置界面的标准组件,它允许开发者以XML方式定义用户界面,然后在活动中...在实际项目中,我们应该根据具体需求进行适当的调整和优化,确保自定义的界面既美观又实用。
android PreferenceActivity中的组件源码~
开发者可以通过重写`onCreate()`方法并设置监听器来获取用户对设置项的更改。 4. **导航**:在`PreferenceScreen`中,可以使用`<intent>`标签来定义跳转其他Activity或Intent的行为,这样用户可以在设置界面中进行...
在PreferenceActivity中,当用户更改了设置后,通常需要刷新应用的状态或者更新UI。这可以通过监听Preference的更改事件来实现。例如,可以在`onPreferenceChange`回调方法中处理这些事件,以确保应用的行为与用户的...
在Android开发中,UI设计是至关重要的一环,而PreferenceActivity是Android系统提供的一种用于构建设置界面的特殊Activity。本篇文章将深入探讨如何利用PreferenceActivity来创建用户交互界面,特别是涉及开启WiFi和...
使用`PreferenceActivity`可以让开发者避免编写大量的UI代码,只需在XML布局文件中定义偏好设置,然后在代码中加载即可。 ### 2. 创建`PreferenceActivity` 首先,我们需要创建一个新的Activity,并让它继承自`...