checkboxpreference中的多重依赖关系android或listpreference的依赖关系

时间:2011-03-30 09:21:47

标签: android preferences listpreference checkboxpreference

例如:我的首选项屏幕中有三个复选框,每个复选框上有3个不同的listpreference(A,B,C)。我想让用户一次只选择一个复选框。我如何实现这一目标?

  1. 首选项屏幕中没有单选按钮

  2. 我无法使用Listpreference,如果我可以使用它

      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"
    
  3. 此Listprefrence的数组为“blue”,“red”,“white”

      

    如果是蓝色的话   ListPreference A取决于蓝色

         

    如果是红色的话   ListPreference B取决于红色

         

    如果是白色的话   ListPreference C取决于白色

    我该怎么做?

    我在谷歌搜索了3-4页,这里几乎所有关于这些的内容但是我找不到任何答案。

    最诚挚的问候,

    提前致谢..

2 个答案:

答案 0 :(得分:14)

您可以覆盖onSharedPreferenceChanged课程中的PreferenceActivity并以编程方式启用/禁用适当的偏好设置:

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
            }
        }
    }

答案 1 :(得分:0)

另一种方法是创建抽象帮助程序类。它使用反射来访问方法registerDependent(),而该方法Preference类是私有的:

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;
    }

}

然后扩展您的checkboxPreference或其他任何类,如下所示:

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);
    }
}

最后,您可以像这样使用新的首选项:

<?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>

后记: 如果您不想使MultiDependecies类成为抽象对象并覆盖findPreferenceInHierarchy函数,则可以使用反射:

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;
}