另一种方法是创建一个抽象助手类。它使用反射来访问该类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>
Post Scriptum:
如果您不想使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;
}