web-dev-qa-db-fra.com

Comment ouvrir ou simuler un clic sur une préférence Android, créée avec XML, par programme?

J'ai une Android avec des préférences déclarées en XML, chargée avec addPreferencesFromResource. L'utilisateur peut ouvrir les préférences, cliquer sur chaque élément et les modifier, tout fonctionne.

J'ai une préférence:

        <ListPreference Android:key="abc"
            Android:title="@string/abc"
            Android:summary="@string/cde"
            Android:persistent="true"/>

Comment puis-je montrer automatiquement la boîte de dialogue des préférences à un utilisateur (sans qu'il soit nécessaire que l'utilisateur accède à l'écran des préférences et clique dessus?).

J'ai essayé ( (Android.preference.DialogPreference) prefMgr.findPreference( "abc" )).showDialog(null), mais dit que c'est une méthode protégée ...? Je l'ai appelé depuis mon activité principale (qui est un PreferenceActivity), c'est pourquoi cela ne peut évidemment pas fonctionner. Mais comment d'autre?

ÉDITER

Je viens de trouver deux threads ( 1 et 2 ) avec l'idée d'utiliser findViewById pour accéder à la préférence, mais sans succès. Il retourne toujours null (le fait pour moi aussi).

Il semble qu'il n'y ait vraiment aucune possibilité de le faire à partir du code.

44
Markus

Vous pourriez avoir étendu ListPreference pour créer votre boîte de dialogue, puis inclure votre propre méthode publique qui appelle la méthode showDialog protégée de ListPreference. Quelque chose comme:

public void show()
{
    showDialog(null);
}

De cette façon, vous ne rencontrerez pas le problème de getOrder () ne fonctionnant pas lorsqu'il existe des groupes de préférences, comme plusieurs personnes l'ont souligné dans les commentaires de votre réponse.

Cela peut être fait avec n'importe quel type de préférence doté d'une méthode showDialog protégée.

23
Jabari

Voir la nouvelle réponse acceptée pour une approche beaucoup plus propre! Cela fonctionnait, mais pas vraiment la manière la plus propre de le faire.


Bon sang, ça m'a pris plusieurs heures, mais ça marche finalement.

La solution est l'appel non documenté public void onItemClick (...) . Il prend plusieurs arguments, et comme indiqué par cette question il peut être utilisé pour simuler un clic en fonction de l'index de l'élément que vous souhaitez appeler.

Mon problème est que l'élément que je veux appeler est profondément imbriqué dans une structure XML. Mais la solution est très simple: ajoutez un key au PreferenceScreen l'élément que vous souhaitez ouvrir se trouve dans:

<PreferenceScreen
    Android:key="pref_key"
    ....
    />
    <ListPreference Android:key="abc"
        Android:title="@string/abc"
        Android:summary="@string/cde"
        Android:persistent="true"/>

</PreferenceScreen>

Et vous pouvez simplement:

// the preference screen your item is in must be known
PreferenceScreen screen = (PreferenceScreen) findPreference("pref_key");

// the position of your item inside the preference screen above
int pos = findPreference("abc").getOrder();

// simulate a click / call it!!
screen.onItemClick( null, null, pos, 0 ); 

Et la boîte de dialogue apparaît!

Ce serait bien d'obtenir le PreferenceScreen un Preference (donc vous n'auriez pas besoin de savoir où est votre Preference), car déplacer la préférence/changer le XML pourrait briser la boîte de dialogue automatique en silence et ne pas être remarqué (s'il n'est pas testé).

Pour cela, j'ai écrit une fonction qui va rechercher dans toutes les préférences et retourner le PreferenceScreen votre préférence est activée, vous n'avez donc pas besoin d'avoir votre écran PreferenceScreen une clé!

private PreferenceScreen findPreferenceScreenForPreference( String key, PreferenceScreen screen ) {
    if( screen == null ) {
        screen = getPreferenceScreen();
    }

    PreferenceScreen result = null;

    Android.widget.Adapter ada = screen.getRootAdapter();
    for( int i = 0; i < ada.getCount(); i++ ) {
        String prefKey = ((Preference)ada.getItem(i)).getKey();
        if( prefKey != null && prefKey.equals( key ) ) {
            return screen;
        }
        if( ada.getItem(i).getClass().equals(Android.preference.PreferenceScreen.class) ) {
            result = findPreferenceScreenForPreference( key, (PreferenceScreen) ada.getItem(i) );
            if( result != null ) {
                return result;
            }
        }
    }

    return null;
}

private void openPreference( String key ) {
    PreferenceScreen screen = findPreferenceScreenForPreference( key, null );
    if( screen != null ) {
        screen.onItemClick(null, null, findPreference(key).getOrder(), 0);
    }
}

// With this, you can call your `Preference` like this from code, you do
// not even have to give your PreferenceScreen a key!
openPreference( "abc" );
37
Markus
 PreferenceScreen preferenceScreen  = (PreferenceScreen) findPreference("pref_key");
    final ListAdapter listAdapter = preferenceScreen.getRootAdapter();
         EditTextPreference editPreference = (EditTextPreference)   findPreference("set_password_preference");

    final int itemsCount = listAdapter.getCount();
    int itemNumber;
    for (itemNumber = 0; itemNumber < itemsCount; ++itemNumber) {
        if (listAdapter.getItem(itemNumber).equals(editPreference)) {
            preferenceScreen.onItemClick(null, null, itemNumber, 0);
            break;
        }
    }
     }
 }  
8
Deepak Goel

Si vous utilisez la bibliothèque de support, vous pouvez ouvrir une boîte de dialogue facilement avec PreferenceManager.showDialog (Preference) .

Dans votre PreferenceFragmentCompat:

getPreferenceManager().showDialog(findPreference("pref_name"));

Notez que le package de préférences de prise en charge présente de nombreux problèmes: style non matériel et il se bloque lors d'une rotation avec une boîte de dialogue ouverte .

6
headsvk

Améliorer deepak goel réponse:

private void openPreference(String key) {
    PreferenceScreen preferenceScreen = getPreferenceScreen();
    final ListAdapter listAdapter = preferenceScreen.getRootAdapter();

    final int itemsCount = listAdapter.getCount();
    int itemNumber;
    for (itemNumber = 0; itemNumber < itemsCount; ++itemNumber) {
        if (listAdapter.getItem(itemNumber).equals(findPreference(key))) {
            preferenceScreen.onItemClick(null, null, itemNumber, 0);
            break;
        }
    }
}
3
azendh