【发布时间】:2011-01-15 11:14:30
【问题描述】:
我有一个扩展 PreferenceActivity 的活动。 我正在从 xml 文件加载首选项。 但在某些情况下,我需要根据我的应用程序状态从屏幕上完全隐藏其中一个首选项。有一个 setEnabled 方法,但这不是我想要的。我想完全从屏幕上删除该偏好。 有可能吗?
【问题讨论】:
标签: android preferences
我有一个扩展 PreferenceActivity 的活动。 我正在从 xml 文件加载首选项。 但在某些情况下,我需要根据我的应用程序状态从屏幕上完全隐藏其中一个首选项。有一个 setEnabled 方法,但这不是我想要的。我想完全从屏幕上删除该偏好。 有可能吗?
【问题讨论】:
标签: android preferences
如果您的Preference 在PreferenceCategory 内,您必须这样做:
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);
【讨论】:
PreferenceCategory。
是的,如果您同时引用了 Preference 及其父项(PreferenceCategory 或 PreferenceScreen)
myPreferenceScreen.removePreference(myPreference);
【讨论】:
removePreference,您可以通过getParent() 获得(参见this answer)。
如果首选项是首选项屏幕的直接子项,这里有一些独立代码:
PreferenceScreen screen = getPreferenceScreen();
Preference pref = getPreferenceManager().findPreference("mypreference");
screen.removePreference(pref);
【讨论】:
findPreference,并从该类别中删除首选项
如果您使用PreferenceFragmentCompat,您可以在 xml 中设置可见性。
您的 xml 中的首选项将自动转换为 AppCompat 版本。然后,您可以在 xml 中使用 'app:isPreferenceVisible' 属性
preferences.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
添加PreferenceFragmentCompat 记录在https://developer.android.com/guide/topics/ui/settings/#inflate_the_hierarchy
例子:
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();
}
}
【讨论】:
如果您想要动态更改首选项的东西,例如在 SwitchPreference 上,我发现最好的方法是将所有子选项放入两个类别容器中。最初您将显示所有内容,然后您只需删除不需要的位。聪明的一点是,您只需在某些内容发生变化时触发重新创建,然后您就不必手动创建任何内容或担心以正确的顺序将内容放回原处。
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();
}
}
我能看到的唯一缺点是屏幕从头开始重新创建时会出现闪光。
【讨论】:
在您的 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
【讨论】:
我推荐使用 v7 首选项,它有 setVisible() 方法。但我还没有尝试过。因此,您必须使用PreferenceFragment 而不是PreferenceActivity。
【讨论】:
getParent(),因此您实际上可以按照this answer 中的说明删除首选项。
在 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);
【讨论】:
这是一种通用的方法,无论偏好是在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;
}
【讨论】:
您可以通过两种方式做到这一点:
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;
}
【讨论】:
setVisible() 从支持库的版本 24.1.0 开始可用。
setVisibile() 方法可以从我试图澄清的 android-x 获得。请不要冒犯。
如果您想评估,并基于该掩码,替代方案可能是
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);
【讨论】:
如果您正在做我认为您正在尝试做的事情(因为我现在正在尝试这样做),启用/禁用首选项可能会更好。因为删除它会将其从首选项屏幕中删除,并且如果您以编程方式制作屏幕,您可能无法将其添加回您想要的位置。
pref.setEnabled(false); pref.setEnabled(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);
}
并创建一个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"/>
无论您喜欢隐藏在哪里(在 PreferenceGroup 中或在根目录中),它都会起作用!
【讨论】: