从屏幕上删除/隐藏首选项

我有一个扩展 PreferenceActivity 的活动。 我正在从 xml 文件加载首选项。 但在某些情况下,我需要完全隐藏其中一个首选项从屏幕上根据我的应用程序状态。有一个 setEnable 方法,但它并不完全是我想要的。我想从屏幕上完全消除这个偏好。 有可能吗?

79642 次浏览

是的,如果您同时引用了 Preference及其父级(PreferenceCategoryPreferenceScreen)

myPreferenceScreen.removePreference(myPreference);

如果你的 PreferencePreferenceCategory之内,你必须这样做:

XML:

<PreferenceCategory
android:key="category_foo"
android:title="foo">


<CheckBoxPreference
android:key="checkPref" />

Java:

CheckBoxPreference mCheckBoxPref = (CheckBoxPreference) findPreference("checkPref");
PreferenceCategory mCategory = (PreferenceCategory) findPreference("category_foo");
mCategory.removePreference(mCheckBoxPref);

如果首选项是首选项屏幕的直接子元素,这里有一些独立的代码:

PreferenceScreen screen = getPreferenceScreen();
Preference pref = getPreferenceManager().findPreference("mypreference");
screen.removePreference(pref);

如果您想要动态更改选项(例如在 Switch Preferences 上) ,我发现最好的方法是将所有子选项放入两个类别容器中。最初你会显示所有的东西,然后你只是删除你不想要的部分。聪明的地方在于,当某些东西发生变化时,你只需要触发重新创建,这样你就不必手动创建任何东西,也不用担心把东西放回正确的顺序。

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
PreferenceCategory prefCatOne= (PreferenceCategory)findPreference("prefCatOne");
PreferenceCategory prefCatTwo= (PreferenceCategory)findPreference("prefCatTwo");
SwitchPreference mySwitchPref= (SwitchPreference)findPreference("mySwitchPref");
PreferenceScreen screen = getPreferenceScreen();
if (mySwitchPref.isChecked()) {
screen.removePreference(prefCatOne);
} else {
screen.removePreference(prefCatTwo);
}
}


public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if (key.equals("mySwitchPref")) {
this.recreate();
}
}

唯一的缺点,我可以看到这一点,是有一个闪光,因为屏幕是重新从头开始。

如果您想评估,并基于这个面具,一个替代方案可能是

SwitchPreference autenticacionUsuario =
(SwitchPreference) findPreference("key_autenticacion_usuario");


final EditTextPreference Username =
(EditTextPreference) findPreference("key_username_mqtt");
final EditTextPreference Password =
(EditTextPreference) findPreference("key_password_mqtt");


if (!autenticacionUsuario.isChecked()) {
PreferenceCategory preferenceCategory =
(PreferenceCategory) findPreference("category_mqtt");
preferenceCategory.removePreference(Username);
preferenceCategory.removePreference(Password);
}

所有这一切必须是内在的

public static class PrefsFragment extends PreferenceFragment {


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

这里有一个通用的方法,不管首选项是在 PreferenceCategory还是 PreferenceScreen之下,它都可以工作。

private void removePreference(Preference preference) {
PreferenceGroup parent = getParent(getPreferenceScreen(), preference);
if (parent == null)
throw new RuntimeException("Couldn't find preference");


parent.removePreference(preference);
}


private PreferenceGroup getParent(PreferenceGroup groupToSearchIn, Preference preference) {
for (int i = 0; i < groupToSearchIn.getPreferenceCount(); ++i) {
Preference child = groupToSearchIn.getPreference(i);


if (child == preference)
return groupToSearchIn;


if (child instanceof PreferenceGroup) {
PreferenceGroup childGroup = (PreferenceGroup)child;
PreferenceGroup result = getParent(childGroup, preference);
if (result != null)
return result;
}
}


return null;
}

我建议使用 v7首选项,它有 setVisible()方法。但我还没试过。因此,您必须使用 PreferenceFragment而不是 PreferenceActivity

在 XML 文件中:

<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:key="preferenceScreen">


<PreferenceCategory
android:key="personalisation"
android:title="your title here">


<ThemedPreference
android:key="animation" />


</PreferenceScreen>

在您的代码中:

PreferenceScreen pPreferenceScreen = (PreferenceScreen) findPreference("preferenceScreen");


PreferenceCategory pCategory = (PreferenceCategory) findPreference("personalisation");
ThemedPreference pThemePref = (ThemedPreference) findPreference("animation");


pPreferenceScreen.removePreference(pCategory); //remove category
pCategory.removePreference(pThemePref);   // remove preference

在 XML 文件中,您可以通过保留标题和摘要标记为空来创建一个隐藏的首选项。

<EditTextPreference
android:defaultValue="toddlerCam"
android:key="save_photo_dir"
/>

因为 Android API 26 getParent()方法是可用的: https://developer.android.com/reference/android/preference/Preference.html#getParent()

不过你可以这样做:

preference.getParent().removePreference(preference);

你可以通过两种方式来做到这一点:

1.如果使用支持库,可以构建首选项树及其父元素的映射,然后使用其父元素删除首选项。下面是生成这样一个映射的函数:

public static Map<Preference, PreferenceGroup> buildPreferenceParentTree(@NonNull final PreferenceScreen preferenceScreen) {
final Map<Preference, PreferenceGroup> result = new HashMap<>();
final Stack<PreferenceGroup> curParents = new Stack<>();
curParents.add(preferenceScreen);
while (!curParents.isEmpty()) {
final PreferenceGroup parent = curParents.pop();
final int childCount = parent.getPreferenceCount();
for (int i = 0; i < childCount; ++i) {
final Preference child = parent.getPreference(i);
result.put(child, parent);
if (child instanceof PreferenceGroup)
curParents.push((PreferenceGroup) child);
}
}
return result;
}
  1. 如果您使用新的 android-x 首选项 API,您可以通过在其上使用 < strong > setVisible 函数来设置可见性。

如果使用 偏好片段,可以在 xml 中设置可见性。

Xml 中的首选项将自动转换为 AppCompat 版本。然后可以在 xml 中使用‘ 应用程序: isPreferenceVisible’属性

Xml

<PreferenceScreen 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">


<CheckBoxPreference
android:defaultValue="false"
android:key="show.navigation"
android:title="Show navigation"
app:isPreferenceVisible="false" />


...

该属性在 https://developer.android.com/guide/topics/ui/settings/components-and-attributes中有文档说明

https://developer.android.com/guide/topics/ui/settings/#inflate_the_hierarchy中记录了添加 PreferenceFragmentCompat

例如:

public class MySettingsActivity extends AppCompatActivity {


public static class MySettingsFragment extends PreferenceFragmentCompat {
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.preferences, rootKey);
}
}


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.settings_container, new MySettingsFragment())
.commit();
}
}

如果你正在做我认为你正在尝试做的事情(因为我正在尝试做) ,启用/禁用首选项可能会更好。因为删除它会将它带出首选项屏幕,而且如果以编程方式创建屏幕,您可能无法将它添加回您想要的位置。

SetEnable (false) ; SetEnable (true) ;

虽然这可能不被推荐使用,但它适用于我现在正在经历的用例。

如果您所需要的只是不显示首选项,即隐藏首选项,那么执行以下操作

findPreference<Preference>("keyName").isVisible = false

代码在 Kotlin

注意: 这是 AndroidX 首选项(不知道是否与前面的首选项相同)

有一个简单的解决办法:

//In your Activity code after finding the preference to hide:
if(pref!=null) {
pref.setEnabled(false);
pref.setSelectable(false);
//Following line will replace the layout of your preference by an empty one
pref.setLayoutResource(R.layout.preference_hidden);
}

然后创建一个偏好-隐藏布局:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="0dp"/>

无论你的偏好是隐藏(在偏好组或根)它将工作!