Question

For example: i have three checkboxes in my preference screen and there is 3 different listpreference(A,B,C) depended on each checkbox. i want to make the user select only one checkbox at a time. How do i achieve this?

  1. There is no radio button in preference screen

  2. I can not use Listpreference , if i can use it

      ListPreference
        android:key="livewallpaper_testpattern"
        android:title="@string/livewallpaper_settings_title"
        android:summary="@string/livewallpaper_settings_summary"
        android:entries="@array/livewallpaper_testpattern_names"
        android:entryValues="@array/livewallpaper_testpattern_prefix"
    

Array of this Listprefrence is "blue"," red", "white"

if it is blue ListPreference A depends on blue

if it is red ListPreference B depends on red

if it is white ListPreference C depends on white

How can i do this?

i searched 3-4 pages in google and here almost everything about these but i could not find any answer.

Best Regards,

Thanks in advance..

Was it helpful?

Solution

You can override onSharedPreferenceChanged in your PreferenceActivity class and enable/disable appropriated Preferences programmatically:

public class MyPreferences extends PreferenceActivity implements OnSharedPreferenceChangeListener {
    ...
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        if (key.equals("livewallpaper_testpattern")) {
            if (/* check if livewallpaper_testpattern equals to blue */) {
                findPreference("ListPreferenceKey_A").setEnabled(true);
                findPreference("ListPreferenceKey_B").setEnabled(false);
                findPreference("ListPreferenceKey_C").setEnabled(false);
            } else if (/* check if livewallpaper_testpattern equals to red */) {
                // enable B, disable A & C
            } else if (/* check id livewallpaper_testpattern equals to white */) {
                // enable C, disable A & B
            }
        }
    }

OTHER TIPS

Another way is to create an abstract helper class. It uses reflection to access the method registerDependent() which sadly is private to the Preference class:

public abstract class MultiDependencies {

    private static final String NOLESHNS="http://nolesh.com";

    private Preference host;        
    private HashMap<String, Boolean> dependencies = new HashMap<>();

    //We have to get access to the 'findPreferenceInHierarchy' function
    //from the extended preference, because this function is protected
    protected abstract Preference findPreferenceInHierarchy(String key);

    public MultiDependencies(Preference host, AttributeSet attrs){

        this.host = host;

        final String dependencyString = getAttributeStringValue(attrs, NOLESHNS, "dependencies", null);

        if (dependencyString != null) {
            String[] dependencies = dependencyString.split(",");
            for (String dependency: dependencies) {
                this.dependencies.put(dependency.trim(), false);
            }
        }
    }

    void onAttachedToActivity(){
        if(isEnabled()) registerDependencies();
    }

    void onDependencyChanged(Preference dependency, boolean disableDependent){
        setDependencyState(dependency.getKey(), !disableDependent);
        setHostState();
    }

    private void setDependencyState(String key, boolean enabled){
        for (Map.Entry<String, Boolean> entry: dependencies.entrySet()) {
            if (entry.getKey().equals(key)) entry.setValue(enabled);
        }
    }

    private String getAttributeStringValue(AttributeSet attrs, String namespace, String name, String defaultValue) {
        String value = attrs.getAttributeValue(namespace, name);
        if(value == null) value = defaultValue;
        return value;
    }

    private void registerDependencies() {
        for (final Map.Entry<String, Boolean> entry: dependencies.entrySet()) {
            final Preference preference = findPreferenceInHierarchy(entry.getKey());

            if (preference != null) {

                try {
                    final Class<Preference> prefClass = Preference.class;
                    final Method registerMethod = prefClass.getDeclaredMethod("registerDependent", Preference.class);
                    registerMethod.setAccessible(true);
                    registerMethod.invoke(preference, host);
                } catch (final Exception e) {
                    e.printStackTrace();
                }

                boolean enabled = preference.isEnabled();
                if(preference instanceof CheckBoxPreference){
                     enabled &= ((CheckBoxPreference) preference).isChecked();
                }

                setDependencyState(preference.getKey(), enabled);
            }
        }
        setHostState();
    }

    private void setHostState(){
        boolean enabled = true;
        for (Map.Entry<String, Boolean> entry: dependencies.entrySet()) {
            if (!entry.getValue()){
                enabled = false;
                break;
            }
        }
        host.setEnabled(enabled);
    }

    public boolean isEnabled(){
        return dependencies.size()>0;
    }

}

Then extend your checkboxPreference or any other class as follows:

public class MultiDependencyCheckboxPrereference extends CheckBoxPreference {

    MultiDependencies multiDependencies;

    public MultiDependencyCheckboxPrereference(Context context, AttributeSet attrs) {
        super(context, attrs);

        multiDependencies = new MultiDependencies(this, attrs) {
            @Override
            protected Preference findPreferenceInHierarchy(String key) {
                //Getting access to the protected function
                return MultiDependencyCheckboxPrereference.this.findPreferenceInHierarchy(key);
            }
        };
    }

    @Override
    protected void onAttachedToActivity() {
        super.onAttachedToActivity();
        multiDependencies.onAttachedToActivity();
    }

    @Override
    public void onDependencyChanged(Preference dependency, boolean disableDependent) {
        if(multiDependencies.isEnabled()) 
            multiDependencies.onDependencyChanged(dependency, disableDependent);
        else super.onDependencyChanged(dependency, disableDependent);
    }
}

Finally, you can use your new preference like this:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:nolesh="http://nolesh.com">

<com.nolesh.android.widgets.MultiDependencyCheckboxPrereference
    android:key="com_nolesh_test"
    android:defaultValue="false"
    android:title="test"
    nolesh:dependencies="com_nolesh_dep1, com_nolesh_dep2"
    />

<CheckBoxPreference
    android:key="com_nolesh_dep1"
    android:defaultValue="false"
    android:title="dependency 1"
    />

<CheckBoxPreference
    android:key="com_nolesh_dep2"
    android:defaultValue="false"
    android:title="dependency 2"
    />

</PreferenceScreen>

Post Scriptum: If you don't want to make the MultiDependecies class abstact and override the findPreferenceInHierarchy function, you can use reflection:

private Preference findPreferenceInHierarchy(String key){
    try {
        final Class<Preference> prefClass = Preference.class;
        final Method registerMethod = prefClass.getDeclaredMethod(
                    "findPreferenceInHierarchy", String.class);
        registerMethod.setAccessible(true);
        return (Preference) registerMethod.invoke(host, key);
    } catch (final Exception e) {
        e.printStackTrace();
    }
    return null;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top