web-dev-qa-db-fra.com

Le sous-écran des préférences ne s'ouvre pas lors de l'utilisation de support.v7.preference

J'essaie d'implémenter des préférences avec des sous-écrans en utilisant AppCompatActivity et support.v7.preference

Selon la documentation, chaque écran PreferenceScreen d'un autre écran PreferenceScreen fonctionne comme un sous-écran et le framework gérera son affichage lorsqu'il est cliqué . http://developer.Android.com/guide/topics/ui/settings. html # Sous-écrans

<PreferenceScreen  xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <!-- opens a subscreen of settings -->
    <PreferenceScreen
        Android:key="button_voicemail_category_key"
        Android:title="@string/voicemail"
        Android:persistent="false">
        <ListPreference
            Android:key="button_voicemail_provider_key"
            Android:title="@string/voicemail_provider" ... />
        <!-- opens another nested subscreen -->
        <PreferenceScreen
            Android:key="button_voicemail_setting_key"
            Android:title="@string/voicemail_settings"
            Android:persistent="false">
            ...
        </PreferenceScreen>
        <RingtonePreference
            Android:key="button_voicemail_ringtone_key"
            Android:title="@string/voicemail_ringtone_title"
            Android:ringtoneType="notification" ... />
        ...
    </PreferenceScreen>
    ...
</PreferenceScreen>

Cela fonctionne correctement en utilisant Activity, PreferenceFragment ... en natif, mais en utilisant AppCompatActivity et PreferenceFragmentCompat, un clic sur l'élément Préférence le met en surbrillance, mais n'ouvre pas le sous-écran.

Je n'ai rien trouvé dans cette lecture de la documentation et du code ... dois-je implémenter des rappels supplémentaires?


EDIT: juste pour être complet ...

Cela fonctionne et ouvre le sous-écran:

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (savedInstanceState == null) {
            getFragmentManager().beginTransaction()
                    .replace(Android.R.id.content, new DemoPreferenceFragment())
                    .commit();
        }
    }

    static public class DemoPreferenceFragment extends PreferenceFragment {

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.preferences);
        }
    }
}

Cela ne fonctionne pas/ouvre le sous-écran:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction()
                    .replace(Android.R.id.content, new DemoPreferenceFragment())
                    .commit();
        }
    }

    static public class DemoPreferenceFragment extends PreferenceFragmentCompat {

        @Override
        public void onCreatePreferences(Bundle bundle, String s) {
            addPreferencesFromResource(R.xml.preferences);
        }
    }
}

Edit: 25/01/2016

Après avoir tripoté avec support.v7.preference pendant quelques jours, j'ai résumé mes conclusions ici, espérant que cela pourrait aider les autres: Comment utiliser support.v7.preference avec AppCompat et potentiel désavantages

23
maxdownunder

Cela ressemble à un bogue dans PreferenceFragmentCompat ou à une insuffisance de documents. Il a la méthode onNavigateToScreen qui est appelée lorsque vous cliquez sur l’élément PreferenceScreen.

Mais la méthode getCallbackFragment () renvoie la valeur null par défaut. Vous devez donc la remplacer dans votre fragment pour la renvoyer. Aussi, vous devez implémenter PreferenceFragmentCompat.OnPreferenceStartScreenCallback.

public class SettingsFragment extends PreferenceFragmentCompat implements PreferenceFragmentCompat.OnPreferenceStartScreenCallback {

    public static SettingsFragment newInstance() {
        return new SettingsFragment();
    }

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        addPreferencesFromResource(R.xml.news_settings);
    }

    @Override
    public Fragment getCallbackFragment() {
        return this;
    }

    @Override
    public boolean onPreferenceStartScreen(PreferenceFragmentCompat preferenceFragmentCompat, PreferenceScreen preferenceScreen) {
        preferenceFragmentCompat.setPreferenceScreen(preferenceScreen);
        return true;
    }
}

Mais cela pose un autre problème lorsque vous ne pouvez pas revenir à votre écran PreferenceScreen initial, 

Une autre solution consiste à remplacer le fragment décrit ici Comment revenir en arrière du sous-écran Préférences vers l'écran principal dans PreferenceFragmentCompat?

17
LackOfKnowledge

Ceci est un exemple de travail complet, j'espère que cela sera utile à quelqu'un.Il couvre l'ouverture du sous-écran des préférences et le retour à l'écran principal des paramètres. 

J'ai suivi ce problème dans Android Tracker Issue Tracker - ici

La documentation officielle ne contient pas la documentation pour le chargement des sous-écrans de préférences - Reportez-vous ici à la documentation officielle-

L’écran principal des paramètres avancés contient 2 cases à cocher et un titre de sous-écran désactivé (paramètres de modèle personnalisés): -

 subscreen title disabled

Une fois que nous avons coché la case Personnalisé, le titre du sous-écran est activé .  subscreen title enabled

En cliquant sur Paramètres du motif personnalisé, le sous-écran s'ouvre dans un nouvel écran.

 enter image description here

Voici l'exemple de code avec documentation: -

Dans le fichier res/xml/preferences.xml: -

    <?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:summary="Trying intro text">
    <PreferenceCategory Android:title="Settings">
        <CheckBoxPreference
            Android:defaultValue="true"
            Android:key="defaultPress"
            Android:title="Default settings" />
        <CheckBoxPreference
            Android:defaultValue="false"
            Android:key="customKey"
            Android:title="Custom" />
        <PreferenceScreen
            Android:key="customPrefKey"
            Android:title="Custom Pattern Settings">
            <PreferenceCategory
                Android:key="customSettingsKey"
                Android:title="Custom Settings">
                <ListPreference
                    Android:defaultValue="4"
                    Android:entries="@array/initialClickArray"
                    Android:entryValues="@array/initialClickValues"
                    Android:key="initialClicks"
                    Android:summary="initialClicksSummary"
                    Android:title="No. Of Clicks" />
                <ListPreference
                    Android:defaultValue="5"
                    Android:entries="@array/initialTimeArray"
                    Android:entryValues="@array/initialTimeValues"
                    Android:key="initialTimeKey"
                    Android:summary="Time to complete clicks"
                    Android:title="Time to complete" />
            </PreferenceCategory>
        </PreferenceScreen>
    </PreferenceCategory>
</PreferenceScreen>

MainActivity.Java doit implémenter l'interface PreferenceFragmentCompat.OnPreferenceStartScreenCallback et ensuite remplacer la méthode-- onPreferenceStartScreen 

public class MainActivity extends AppCompatActivity implements PreferenceFragmentCompat.OnPreferenceStartScreenCallback {

    private static final String TAG = MainActivity.class.getName();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        FragmentManager fragmentManager = getSupportFragmentManager();
        Fragment fragment = null;
        if (savedInstanceState == null) {
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            fragment = new AdvancedSettingsFragment().newInstance("Advanced Setting");
            fragmentTransaction.add(R.id.fragment_container, fragment);
            fragmentTransaction.commit();
        }
    }

    @Override
        public boolean onPreferenceStartScreen(PreferenceFragmentCompat preferenceFragmentCompat,
                                           PreferenceScreen preferenceScreen) {
        Log.d(TAG, "callback called to attach the preference sub screen");
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        AdvancedSettingsSubScreenFragment fragment = AdvancedSettingsSubScreenFragment.newInstance("Advanced Settings Subscreen");
        Bundle args = new Bundle();
        //Defining the sub screen as new root for the  subscreen
        args.putString(PreferenceFragmentCompat.ARG_PREFERENCE_ROOT, preferenceScreen.getKey());
        fragment.setArguments(args);
        ft.replace(R.id.fragment_container, fragment, preferenceScreen.getKey());
        ft.addToBackStack(null);
        ft.commit();
        return true;
    }

Pour l’écran principal Paramètres (fragment): -

public class AdvancedSettingsFragment extends PreferenceFragmentCompat {
    private static final String TAG = AdvancedSettingsFragment.class.getName();
    public static final String PAGE_ID = "page_id";

    public static AdvancedSettingsFragment newInstance(String pageId) {
        AdvancedSettingsFragment f = new AdvancedSettingsFragment();
        Bundle args = new Bundle();
        args.putString(PAGE_ID, pageId);
        f.setArguments(args);
        return (f);
    }

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        // Load the preferences from an XML resource
        addPreferencesFromResource(R.xml.preferences);
        final CheckBoxPreference customPreference = (CheckBoxPreference) findPreference("customKey");
        final Preference customSettings = (Preference) findPreference("customPrefKey");
        // First time loading the preference screen, we check the saved settings and enable/disable the custom settings, based on the custom check box
        //get the customSettings value from shared preferences
        if (getCustomSettings(getActivity())) {
            customPreference.setChecked(true);
            customSettings.setEnabled(true);
        } else {
            customPreference.setChecked(false);
            customSettings.setEnabled(false);
        }
        customPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
            @Override
            public boolean onPreferenceChange(Preference preference, Object selectedValue) {
                Log.d(TAG, "Inside on preference change of custom checkbox selection " + selectedValue.getClass());
                if ((Boolean) selectedValue) {
                    customSettings.setEnabled(true);
                }else{
                    customSettings.setEnabled(false);
                }
                return true;
            }
        });
    }
    private boolean getCustomSettings(Context context) {
        return PreferenceManager.getDefaultSharedPreferences(getActivity()).getBoolean("customKey", false);
    }
}

et enfin pour le chargement du sous-écran:

public class AdvancedSettingsSubScreenFragment extends PreferenceFragmentCompat {
    private static final String TAG = AdvancedSettingsSubScreenFragment.class.getName();
    public static final String PAGE_ID = "page_id";

    public static AdvancedSettingsSubScreenFragment newInstance(String pageId) {
        AdvancedSettingsSubScreenFragment f = new AdvancedSettingsSubScreenFragment();
        Bundle args = new Bundle();
        args.putString(PAGE_ID, pageId);
        f.setArguments(args);
        return (f);
    }

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        // rootKey is the name of preference sub screen key name , here--customPrefKey
        setPreferencesFromResource(R.xml.preferences, rootKey);
        Log.d(TAG, "onCreatePreferences of the sub screen " + rootKey);
    }
}
14
Nicks

Une chose extrêmement importante dont vous avez besoin, vous vous en souvenez:

Votre écran Préférence doit contenir:

Android:key="name_a_unique_key"

Sinon, cela ne fonctionnera pas. J'ai passé des heures avec ça

2
Richard Mai

Remplacer PreferenceFragmentCompat.OnPreferenceStartScreenCallback

et l'ajout de ce qui suit à mon fragment de préférence a sauvé ma journée

@Override
public Fragment getCallbackFragment() {
    return this;
}

@Override
public boolean onPreferenceStartScreen(PreferenceFragmentCompat caller, PreferenceScreen pref) {
    caller.setPreferenceScreen(pref);
    return true;
}

Ma version de préférence est

compile 'com.Android.support:preference-v7:25.0.0'
0
Youness

Il semble que Google ait finalement décidé de supporter cela dans la nouvelle préférence AndroidX 1.1.0-alpha d'AndroidX.

Cette vidéo d'Android Dev Summit couvre quelque chose sur l'écran de préférence sous-écran.

0
Dewey Reed