我的Activity
扩展了PreferenceActivity
。
在onBuildHeaders
中,我加载了我在XML中定义的preference-headers
。
@Override
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.admin_preference_headers, target);
}
这是XML文件本身。
<?xml version="1.0" encoding="utf-8"?>
<preference-headers
xmlns:android="http://schemas.android.com/apk/res/android">
<header android:fragment="..."
android:icon="@drawable/image"
android:title="title"
android:summary="summery" />
</preference-headers>
如何停用这些标题,使它们变灰,使它们无法点击?
我的猜测是操纵PreferenceActivity的ListView项目,但我不确定该怎么做。
答案 0 :(得分:2)
一种可能性是覆盖扩展isEnabled(int position)
的适配器中的ArrayAdapter<Header>
。这会使项目默认不可点击,然后您可以在getView(int position, View convertView, ViewGroup parent)
方法中将文本设为灰色。
然后在PreferenceActivity
中,您将覆盖setListAdapter(ListAdapter adapter)
以使用自定义适配器调用super
。
答案 1 :(得分:1)
dodkoc的回答是正确的,但还不完整。
假设您根据偏好设置禁用标头。在这种情况下,如果您只是覆盖setListAdapter()
方法并将其与自定义适配器一起提供,则更改该首选项时,标题列表将不会更新。这是因为PreferenceActivity
在setListAdapter()
方法中仅调用onCreate()
一次。拨打invalidateHeaders()
也无济于事。
所以我就是这样做的:
PreferenceActivity
源代码中的适配器类,并添加了一个方法,当应该启用给定位置的标头时,该方法返回true。<强> HeaderAdapter 强>
private static class HeaderAdapter extends ArrayAdapter<Header> {
private static class HeaderViewHolder {
ImageView icon;
TextView title;
TextView summary;
}
private LayoutInflater mInflater;
private int mLayoutResId;
private boolean mRemoveIconIfEmpty;
public HeaderAdapter(Context context, List<Header> objects, int layoutResId, boolean removeIconBehavior) {
super(context, 0, objects);
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mLayoutResId = layoutResId;
mRemoveIconIfEmpty = removeIconBehavior;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
HeaderViewHolder holder;
View view;
if (convertView == null) {
view = mInflater.inflate(mLayoutResId, parent, false);
holder = new HeaderViewHolder();
holder.icon = (ImageView) view.findViewById(R.id.preference_header_list_item_icon);
holder.title = (TextView) view.findViewById(R.id.preference_header_list_item_title);
holder.summary = (TextView) view.findViewById(R.id.preference_header_list_item_summary);
view.setTag(holder);
} else {
view = convertView;
holder = (HeaderViewHolder) view.getTag();
}
// All view fields must be updated every time, because the view may be recycled
Header header = getItem(position);
if (mRemoveIconIfEmpty) {
if (header.iconRes == 0) {
holder.icon.setVisibility(View.GONE);
} else {
holder.icon.setVisibility(View.VISIBLE);
holder.icon.setImageResource(header.iconRes);
}
} else {
holder.icon.setImageResource(header.iconRes);
}
boolean isEnabled = isHeaderEnabled(position);
holder.title.setText(header.getTitle(getContext().getResources()));
int enabledColor = getContext().getResources().getColor(R.color.text);
int disabledTitleColor = getContext().getResources().getColor(R.color.text_disabled);
holder.title.setTextColor(isEnabled ? enabledColor : disabledTitleColor);
CharSequence summary = header.getSummary(getContext().getResources());
if (!TextUtils.isEmpty(summary)) {
holder.summary.setVisibility(View.VISIBLE);
holder.summary.setText(summary);
int disabledSummaryColor = getContext().getResources().getColor(R.color.secondary_text_disabled);
holder.summary.setTextColor(isEnabled ? enabledColor : disabledSummaryColor);
} else {
holder.summary.setVisibility(View.GONE);
}
return view;
}
public boolean isHeaderEnabled(int position) {
boolean isEnabled = true;
if (position == 2) {
String prefValue = PreferenceManager.getDefaultSharedPreferences(getContext()).getString(PREF_KEY, null);
if (prefValue != null) {
if (//TODO Your condition to disable the header based on prefValue)
isEnabled = false;
}
}
return isEnabled;
}
}
注意:您不希望覆盖isEnabled()
中的ArrayAdapter
方法,以便为要禁用的项目返回false。这会混淆Android 5.0(Lollipop)中ListView中的分隔符。如果项目的isEnabled()
返回false,则该项目周围的分隔符将在Android 5.0中消失。因此,我创建了另一个名为isHeaderEnabled()
的方法来检查项目是否应该启用。
<强> preference_header_item.xml 强>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/activatedBackgroundIndicator"
android:gravity="center_vertical"
android:minHeight="48dp"
android:paddingRight="?android:attr/scrollbarSize">
<ImageView
android:id="@+id/preference_header_list_item_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginEnd="6dp"
android:layout_marginStart="6dp" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="6dp"
android:layout_marginLeft="2dp"
android:layout_marginRight="6dp"
android:layout_marginTop="6dp"
android:layout_weight="1">
<TextView
android:id="@+id/preference_header_list_item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@+id/preference_header_list_item_summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/preference_header_list_item_title"
android:layout_below="@+id/preference_header_list_item_title"
android:ellipsize="end"
android:maxLines="2"
android:textAppearance="?android:attr/textAppearanceSmall" />
</RelativeLayout>
</LinearLayout>
onPostResume()
中的onBuildHeaders()
,onListItemClick()
和PreferenceActivity
方法。在onPostResume()
方法中,我调用invalidateHeader()
重新创建标题列表。但是这个列表没有传递给列表适配器,因此ListView不会自动更新。所以我在onBuildHeaders()
方法中手动执行此操作。最后,由于我没有覆盖isEnabled()
中的ArrayAdapter
方法以针对禁用的项返回false,因此用户仍然可以单击已禁用的标头。因此,我覆盖了onListItemClick()
方法并绕过了对已禁用标头的超级调用。SettingsActivity.java(仅显示相关方法)
@Override
protected void onPostResume() {
super.onPostResume();
invalidateHeaders();
}
@Override
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.pref_headers, target);
// Updating summary to indicate why the header is disabled as per the android design guideline
String prefValue = PreferenceManager.getDefaultSharedPreferences(this).getString(PREF_KEY, null);
if (prefValue != null) {
if (//TODO Your condition to disable the header based on prefValue) {
target.get(2).summary = "Not applicable because you have not enabled something";
} else {
target.get(2).summary = null;
}
}
// Creating a new adapter based on the new header list and passing it to the ListView
HeaderAdapter adapter = new HeaderAdapter(this, target, R.layout.preference_header_list_item, true);
setListAdapter(adapter);
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
if (((HeaderAdapter) getListView().getAdapter()).isHeaderEnabled(position))
super.onListItemClick(l, v, position, id);
}
注意:如果您处于多窗格模式,则可能需要在相关偏好设置的invalidateHeaders()
方法中调用OnPreferenceChangeListener.onPreferenceChange()
,因为onResume()
将在不同标题的内容之间移动时不会被调用。
答案 2 :(得分:0)
在我看来,调整PreferenceActivity现有布局的最简单方法是获取当前的适配器,并通过对其进行装饰来尽可能少地进行更改。
如
@Override
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(...);
final ListAdapter originalAdapter = getListAdapter();
final ArrayAdapter<Header> adapter = new ArrayAdapter<Header>(this, 0, target) {
@NonNull
@Override
public View getView(final int position, @Nullable final View convertView, @NonNull final ViewGroup parent) {
final View view = originalAdapter.getView(position, convertView, parent);
// alter some view based on its position
if (position == 2) {
((TextView) view.findViewById(android.R.id.title))
.setTextColor(ContextCompat.getColor(Activity.this, android.R.color.secondary_text_dark_nodisable));
}
return view;
}
};
setListAdapter(adapter);
}
这样,您就不必在PreferencesActivity中遇到各种UX不一致。
除非注意:不能使用PreferenceActivity或任何与之相关的API 。这是纯粹的邪恶!