28

I have a ListPreference which look something like this:

<ListPreference
android:title="Choose item"
android:summary="..."
android:key="itemList"
android:defaultValue="item1"
android:entries="@array/items"
android:entryValues="@array/itemValues" />

Then, I have another preference which should only be enabled if "item3" is selected in the ListPreference.

Can I somehow accomplish this with android:dependency? Something like android:dependency="itemList:item3"

Thanks!

shuwo
  • 453
  • 2
  • 6
  • 10

4 Answers4

30

The only way you can do something like this is programmaticly.

You'd have to set up an change listener on the ListPreference and then enable/disable the other one.

itemList = (ListPreference)findPreference("itemList");
itemList2 = (ListPreference)findPreference("itemList2");
itemList.setOnPreferenceChangeListener(new
Preference.OnPreferenceChangeListener() {
  public boolean onPreferenceChange(Preference preference, Object newValue) {
    final String val = newValue.toString();
    int index = itemList.findIndexOfValue(val);
    if(index==3)
      itemList2.setEnabled(true);
    else
      itemList2.setEnabled(false);
    return true;
  }
});

If I were you I wouldn't even show the second preference if the first isn't set properly. To do that you have to declare the preference manually (not in the XML) and add/remove it instead of enabling/disabling.

Now isn't this the bestest answer you've ever seen?!

Emmanuel

Emmanuel
  • 16,791
  • 6
  • 48
  • 74
  • 5
    I'll go out on a limb and say that this is the bestestest answer I've ever seen. – Juozas Kontvainis Mar 07 '12 at 14:56
  • 3
    @Emmanuel: itemList and itemList2 variables should be declared final. Anyway, I voted up, because your answer worked great for me! – Giorgio Barchiesi Aug 13 '12 at 16:37
  • 1
    Would it be possible to have itemList2 depende on a *hidden* boolean value (a preference that doesn't show up on the preference screen), and then just set this hidden value to true or false in your code above? The effect would be the same, but I'm thinking it would be slightly more convenient if you had many preferences depending on itemList (instead of just one). If possible, how could you hide this value? – Malabarba Apr 17 '13 at 14:51
  • i have another XML file for hidden preferences i dont want to show in the activity (just for internal use). You can declare it that way and never load it on a preference activity, while you can access (read/write) to it like the other preferences – nsL Oct 13 '13 at 10:37
  • Just tried the solution. Works but when user changes screen orientation disabled control becomes enabled again. – Cheburek Dec 03 '14 at 13:32
7

Subclass ListPreference class, and override setValue and shouldDisableDependence methods.

setValue will call notifyDependencyChange(shouldDisableDependents()) after super.setValue when the value is actually changed.

shouldDisableDependence returns false only if the current value is item3, or any other desired value stored in mDepedenceValue.

@Override
public void setValue(String value) {
    String mOldValue = getValue();
    super.setValue(value);
    if (!value.equals(mOldValue)) {
        notifyDependencyChange(shouldDisableDependents());
    }
}

@Override
public boolean shouldDisableDependents() {
    boolean shouldDisableDependents = super.shouldDisableDependents();
    String value = getValue();
    return shouldDisableDependents || value == null || !value.equals(mDepedenceValue);
}
Dalija Prasnikar
  • 27,212
  • 44
  • 82
  • 159
Water dragon
  • 91
  • 1
  • 3
6

I tried to edit @waterdragon solution but it was "peer rejected". Not sure why because it is still his solution but provides a concrete example.

Subclass ListPreference class, and override setValue and shouldDisableDependence methods.

setValue will call notifyDependencyChange(shouldDisableDependents()) after super.setValue when the value is actually changed.

shouldDisableDependence returns false only if the current value is item3, or any other desired value stored in mDepedenceValue.

package xxx;

import android.content.Context;
import android.content.res.TypedArray;
import android.preference.ListPreference;
import android.util.AttributeSet;

import xxx.R;

public class DependentListPreference extends ListPreference {

    private final String CLASS_NAME = this.getClass().getSimpleName();
    private String dependentValue = "";

    public DependentListPreference(Context context) {
        this(context, null);
    }
    public DependentListPreference(Context context, AttributeSet attrs) {
        super(context, attrs);

        if (attrs != null) {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DependentListPreference);
            dependentValue = a.getString(R.styleable.DependentListPreference_dependentValue);
            a.recycle();
        }
    }

    @Override
    public void setValue(String value) {
        String mOldValue = getValue();
        super.setValue(value);
        if (!value.equals(mOldValue)) {
            notifyDependencyChange(shouldDisableDependents());
        }
    }

    @Override
    public boolean shouldDisableDependents() {
        boolean shouldDisableDependents = super.shouldDisableDependents();
        String value = getValue();
        return shouldDisableDependents || value == null || !value.equals(dependentValue);
    }
}

Update your attrs.xml:

<attr name="dependentValue" format="string" />

<declare-styleable name="DependentListPreference">
    <attr name="dependentValue" />
</declare-styleable>

and inside your preference xml tie it to any other preference that depends on it:

    <xxx.DependentListPreference
        android:key="pref_key_wifi_security_type"
        android:title="Wi-Fi Security Type"
        app:dependentValue="1"
        android:entries="@array/wifi_security_items"
        android:entryValues="@array/wifi_security_values" />

    <EditTextPreference
        android:key="pref_key_wifi_security_key"
        android:title="WPA2 Security Key"
        android:summary="Tap to set a security key"
        android:password="true"
        android:dependency="pref_key_wifi_security_type" />
ShellDude
  • 579
  • 6
  • 12
0

in the xml add the line

app:isPreferenceVisible="false"

Then add an onClickListener to item3 in the java that sets the item to true when selected