web-dev-qa-db-fra.com

Android - Conserver l'élément de ListView en surbrillance une fois que l'on a cliqué dessus

J'ai donc une activité avec 2 widgets ListView, lorsque vous sélectionnez une valeur dans le premier, le second est rempli avec les valeurs liées à la sélection dans la première ListView. Ce mécanisme fonctionne sans problème, mais je souhaite maintenant que les choix des utilisateurs restent en surbrillance. J'ai lu une bonne quantité de questions liées à ce sujet et il semble qu'il existe une myriade de moyens pour y parvenir mais après avoir essayé environ 4-5 d'entre eux, je ne peux toujours pas le faire fonctionner.

Je travaille sur la seconde ListView en utilisant l'attribut XML Android:listSelector="#CCCCCC", mais cela semble avoir été nettoyé une fois qu'une OnItemClickListener est introduite dans le mélange (comme celle que j'utilise sur ma première ListView).

Jusqu'ici voici ce que j'ai:

Personnalisé OnItemClickListener J'ai trouvé en parcourant diverses réponses concernant ce sujet (légèrement modifié afin de pouvoir charger mes informations la deuxième liste): 

private class ItemHighlighterListener implements OnItemClickListener {

    private View oldSelection = null;

    public void clearSelection() {
        if(oldSelection != null) {
            oldSelection.setBackgroundColor(Android.R.color.transparent);
        }
    }

    public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
        clearSelection();
        oldSelection = view;
        view.setBackgroundDrawable(view.getContext().getResources().getDrawable(R.drawable.list_selector));
        loadClubs(mXMLPortalOptions.getRegion(pos).getId());
        mClubList.setAdapter(new ArrayAdapter<String>(getApplicationContext(), R.layout.list_item_white, mClubs));
    }
}

Voici mon fichier list_selector.xml

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

    <item Android:state_selected="true"><shape>
            <solid Android:color="#CCCCCC" />
        </shape></item>

    <item Android:state_selected="false"><shape>
            <solid Android:color="#FFFFFF" />
        </shape></item>

</selector>

La méthode (OnItemClick) est appelée et exécutée, mais l'arrière-plan de ma ListItem reste de la même couleur: /

Je ne peux pas croire que cette tâche simple s'est avérée si compliquée.

Si j'ai omis du code qui pourrait être utile ou si ma question manque de détails, n'hésitez pas à le préciser et je ferai de mon mieux pour m'expliquer.

36
Jean-Philippe Roy

Mettez une variable de position pour l'élément sélectionné. Changer la position dans la méthode onItemClicked(). Vérifiez la position sélectionnée dans List Adapter dans getView() et définissez l'arrière-plan de l'élément sélectionné.

public class TestAdapter extends BaseAdapter
{
    private Context context;
    private ArrayList<TestList> testList;
    private int selectedIndex;
    private int selectedColor = Color.parseColor("#1b1b1b");

    public TestAdapter(Context ctx, ArrayList<TestList> testList)
    {
        this.context = ctx;
        this.testList = testList;
        selectedIndex = -1;
    }

    public void setSelectedIndex(int ind)
    {
        selectedIndex = ind;
        notifyDataSetChanged();
    }

    @Override
    public int getCount()
    {
        return testList.size();
    }

    @Override
    public Object getItem(int position)
    {
        return testList.get(position);
    }

    @Override
    public long getItemId(int position)
    {
        return position;
    }

    private class ViewHolder
    {
        TextView tv;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent)
    {
        View vi = convertView;
        ViewHolder holder;
        if(convertView == null)
        {
            vi = LayoutInflater.from(context).inflate(R.layout.test_list_item, null);
            holder = new ViewHolder();

            holder.tv = (TextView) vi;

            vi.setTag(holder);
        }
        else
        {
            holder = (ViewHolder) vi.getTag();
        }

        if(selectedIndex!= -1 && position == selectedIndex)
        {
            holder.tv.setBackgroundColor(Color.BLACK);
        }
        else
        {
            holder.tv.setBackgroundColor(selectedColor);
        }
        holder.tv.setText("" + (position + 1) + " " + testList.get(position).getTestText());

        return vi;
    }

}

Définissez maintenant la variable selectedIndex quand un élément de la liste a cliqué.

public class TestActivity extends Activity implements OnItemClickListener
{
    // Implemented onItemClickListener

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id)
    {
        adapter.setSelectedIndex(position);
    }
}
61
Shaiful

Pour développer la bonne solution de Shaiful, vous pourriez ne pas le forcer à travailler dans votre situation.

Si vous utilisez votre code dans public void onListItemClick(ListView l, View v, int index, long id), si vous utilisez des fragments et devez déclarer une interface au lieu d'implémenter OnListItemClickListener, ou tout ce qui entraîne votre IDE à générer des erreurs, vous devrez peut-être accéder à des variables et des méthodes statiquement.

public static int selectedPosition = 0;
ArrayAdapter<Your_obj> adapter = null;

@Override
public void onListItemClick(ListView l, View v, int index, long id) {
    super.onListItemClick(l, v, index, id);

        selectedPosition = index;
        Your_adapter.setSelectedIndex(selectedPosition);
        adapter.notifyDataSetChanged();
}

Et dans Your_adapter:

private static int selectedIndex;

//public Your_adapter...

public static void setSelectedIndex(int ind) {
    selectedIndex = ind;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    WellHolder holder = null;

    if (null == convertView) {

                //set up your "holder"
    }

    if (position == selectedIndex) {
        convertView.setBackgroundColor(convertView.getResources().getColor(R.color.cyan));
    }
    else {
        convertView.setBackgroundColor(convertView.getResources().getColor(R.color.silver));
    }

    return convertView;
}

Parmi les autres différences, vous ne devez initialiser aucune variable avec la valeur "0" ou "-1", et notifyDataSetChanged () est appelé dans votre activité.

Encore une fois, merci pour votre solution @Shaiful. Cela m'a certainement aidé à gagner du temps en essayant de faire fonctionner ce qui est par défaut dans iOS pour Android, tout en évitant le sélecteur/élément/focus/pressé/etc.

5
whyoz

J'ai fait face à un problème similaire. C'est ma solution:

Commencez par ajouter un sélecteur de liste personnalisé à votre affichage de liste:

<ListView
    Android:id="@+id/list"
    Android:layout_width="match_parent"
    Android:layout_height="fill_parent"
    Android:listSelector="@drawable/listselector" />

Dans listselector.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <item Android:state_accelerated="false"
        Android:drawable="@drawable/bg" />
</selector>

Et enfin un fichier bg.xml avec la couleur de votre surbrillance:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <solid Android:color="#33b5e6"/>
</shape>
4
zjadarka
//create a list_itemselectorin drawable folder
//you will get the list item selected background color change once you select //the item

    <selector xmlns:Android="http://schemas.Android.com/apk/res/Android">

        <!-- Focused State -->
        <item Android:state_focused="true"><shape>
                <solid Android:color="#66FFFFFF" />
            </shape></item>
        <!-- Pressed State -->

        <item Android:state_pressed="true"><shape>
                <solid Android:color="@color/Black" />
            </shape></item>

        <!-- Default State -->
        <item><shape>
                <solid Android:color="@color/Black" />
            </shape></item>

    </selector>


    //create a list in layout folder
      <ListView
            Android:id="@+id/mySlidingList"
            Android:layout_width="match_parent"
            Android:layout_height="match_parent"
            Android:choiceMode="singleChoice"
            Android:divider="@color/GrayHot"
            Android:dividerHeight="1dip"
            Android:listSelector="@drawable/list_itemselector"
            Android:scrollbars="none" />

// Et voir la sortie.

2
DeepakPanwar

Je pense que la solution la meilleure et la plus simple est la suivante. Vous n'avez pas besoin de définir un Android:listSelector sur le ListView lui-même ou d'apporter des modifications à l'adaptateur. Vous n'avez pas même besoin d'appeler un _setSelection(position) dans la OnItemClickListener car il est traité automatiquement.

  1. Définir sur votre ListView:

    Android:choiceMode="singleChoice"
    
  2. Définir l'arrière-plan de l'élément de liste lui-même:

    Android:background="?android:attr/activatedBackgroundIndicator"
    
  3. C'est tout.

De cette façon, vous obtiendrez un comportement système par défaut. C'est comme ça que ça se passe dans la disposition par défaut Android.R.layout.simple_list_item_activated_1

2
Robyer

Je le cherchais il y a deux semaines et le résultat est que ce n'est pas possible avec un sélecteur pouvant être tiré . Pour plus d'informations, lisez cet article sur le blog des développeurs Android: Touch Mode

En résumé: l'élément est sélectionné uniquement lorsque votre doigt est à l'écran. 

Une autre possibilité est d’enregistrer quel élément est sélectionné dans une var et Paint différent en utilisant votre adaptateur personnalisé, comme le dit Shaiful.

2
i.masm

Pour résumer ce post et peut-être aider quelqu'un d'autre à l'avenir, je suggère la réponse :)

Premièrement, nous devons créer un fichier res/drawable/list_item_background.xml avec le contenu suivant:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <item
        Android:state_activated="true"
        Android:drawable="@color/list_item_activated" />
    <item
        Android:drawable="@color/list_item_default" />
</selector>

Spécifiez vos ressources disponibles, bien sûr. Et vous pouvez également ajouter d'autres éléments <item> avec différents états, tels que state_pressed, state_focused etc.

Ensuite, nous devrions définir le paramètre background sur notre élément de liste personnalisé ViewGroup élément (f.i. res/layout/list_item_layout.xml) comme ceci:

Android:background="@drawable/list_item_background"

L'étape suivante consiste à modifier notre classe Adapter personnalisée. Voici le fragment de code suivant:

public class CustomAdapter extends BaseAdapter {
    private List<Item> items;
    private LayoutInflater itemInflater;        
    private int selectedIndex; // add this

    public CustomAdapter(Context c, List<Item> items) {
        this.items = items;
        this.itemInflater = LayoutInflater.from(c);
        selectedIndex = -1; // add this
    }

    /* add this */
    public void setSelectedIndex(int index) {
        selectedIndex = index;
        notifyDataSetChanged();
    }

    /* other adapter's stuff */

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(convertView == null) {
            convertView = itemInflater.inflate(R.layout.list_item_layout, parent, false);
        }

        // add this
        convertView.setActivated(selectedIndex != -1 && position == selectedIndex);

        /* do some stuff */

        return convertView;
    }
}

Enfin, nous devrions appeler la méthode de l'adaptateur setSelectedIndex(position) dans la méthode onItemClick(...) de AdapterView.OnItemClickListener.

public class YourActivity extends Activity
        implements AdapterView.OnItemClickListener {

    private CustomAdapter mCustomAdapter;

    /* activity implementation */

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        mCustomAdapter.setSelectedIndex(position);
    }
}

Maintenant, nous pouvons être satisfaits des éléments de liste appropriés soulignant :)

P.S. Si nous voulons activer le mode à choix multiples sur notre liste, nous allons simplement placer la chaîne suivante dans notre classe d'activité où l'occurrence listView est conservée:

listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

Ainsi, nous aurons les éléments multiples appropriés en surbrillance.

- J'espère que ça aide n'importe qui :)

0
Eugene Matiyuk

Il existe une solution simple, entièrement XML, qui a fonctionné pour moi . Premièrement, définissez XML-dessinable avec un code de sélecteur dans lequel l'état "normal" correspondra à l'état visuel "sélectionné non exprimé" d'un élément de la liste, et state_pressed = true État visuel "pressé" . Exemple de fichier "custom_item_selector.xml", ressemblant à la sélection bleue Holo:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <item Android:state_pressed="true">
        <shape Android:shape="rectangle">
            <solid
                Android:color="#643292ff">
            </solid>
            <stroke
                Android:width="1dp"
                Android:color="#c83292ff">
            </stroke>
        </shape>
    </item>
    <item>
        <shape Android:shape="rectangle">
            <solid
                Android:color="#323292ff">
            </solid>
            <stroke
                Android:width="1dp"
                Android:color="#783292ff">
            </stroke>
        </shape>
    </item>
</selector>

(peut également définir l'état ciblé à cet endroit) . Deuxièmement, appliquez cet élément pouvant être dessiné au xml en tant que listSelector de ListView et définissez son choix en mode souhaité:

<ListView
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:id="@+id/listView"
            Android:choiceMode="singleChoice"
            Android:listSelector="@drawable/custom_item_selector"/>

C'est tout. Il permet de définir différents états visuels pour les éléments "simplement sélectionnés" et "sélectionnés", en rendant par exemple les éléments plus clairs sur la presse.

0
jetc

Pour que les éléments de la liste (sélection multiple) restent en surbrillance, suivez les étapes ci-dessous (activé).

1. Définir l'arrière-plan pour afficher la disposition des éléments comme dessinable.

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
        Android:layout_width="match_parent"
        Android:layout_height="40dp"
        Android:background="@drawable/list_item_selector">

        <ImageView
            Android:id="@+id/icon"
            Android:layout_width="22px"
            Android:layout_height="22px"
            Android:layout_marginLeft="4px"
            Android:layout_marginRight="10px"
            Android:layout_marginTop="4px"
            Android:src="@mipmap/ic_launcher" >
        </ImageView>

        <TextView
            Android:id="@+id/label"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:text="@+id/label"
            Android:textSize="20px" >
        </TextView>
    </LinearLayout>

2. sélecteur pouvant être dessiné

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

<item Android:state_pressed="true"     Android:drawable="@Android:color/holo_red_light" />

<item Android:state_activated="true" Android:drawable="@Android:color/holo_orange_dark" />

</selector>

3. Liste de vues en mode choix multiple

getListView (). setChoiceMode (ListView.CHOICE_MODE_MULTIPLE);

Lorsque vous appuyez sur:  enter image description here

L'image ci-dessous montre, lorsque l'utilisateur a sélectionné plusieurs éléments de la liste.

Lorsque activé:  enter image description here

0
Annada

Si vous pouvez utiliser un dessin pour afficher listItem Highlighted, utilisez le code suivant: -

listView.setSelector(R.drawable.bg_image);

Ça marche.

0
Suresh Sharma