La selección de ListView permanece persistente después de salir del modo de elección


Tengo una subclase ListView que permito selecciones cuando la barra de acción de contexto (CAB) está activa. La CAB se establece como una devolución de llamada al evento onItemLongClick:

public boolean onCreateActionMode(ActionMode mode, Menu menu) {
    // Inflate a menu resource providing context menu items
    MenuInflater inflater = mode.getMenuInflater();
    inflater.inflate(context_menu, menu);
    getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
    return true;
}

Esto está bien, y la vista de lista funciona como se espera, con el elemento seleccionado actualmente permanece resaltado cuando se toca.

Cuando cierro la CABINA, quiero que la vista de lista vuelva a la normalidad (es decir, al modo Táctil). El problema es que el último elemento seleccionado permanece resaltado indefinidamente, independientemente de los métodos Trato de aclararlo:

public void onDestroyActionMode(ActionMode mode) {
    //Unselect any rows
    ListView lv = getListView();
    lv.clearChoices(); // Has no effect
    lv.setChoiceMode(ListView.CHOICE_MODE_NONE); // Has no effect on the highlighted item 
    lv.setFocusable(false); // Has no effect
    lv.setSelection(0); // Has no effect
    mActionMode = null;
}

Alguna sugerencia?

Author: Nikola K., 2012-03-18

11 answers

La razón principal del problema es que una vez que el modo de selección ListView se cambia a CHOICE_MODE_NONE, el marco optimiza la operación clear ya que ya no admite 'selecciones'. He mejorado un poco las soluciones anteriores borrando el estado de selección manualmente y luego configurando el modo de manera retardada para que el marco tenga su turno para borrar el estado antes de convertir el modo a CHOICE_MODE_NONE.

final ListView lv = getListView();
lv.clearChoices();
for (int i = 0; i < lv.getCount(); i++)
    lv.setItemChecked(i, false);
lv.post(new Runnable() {
    @Override
    public void run() {
        lv.setChoiceMode(ListView.CHOICE_MODE_NONE);
    }
});
 34
Author: Rudi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-02 09:01:54

Me enfrenté al mismo problema y ya que solicitar el diseño no resuelve el problema para mí tampoco implementé un pequeño truco que funciona para mí. Tal vez este es el mismo problema porque estoy cambiando entre CHOICE_MODE_SINGLE y CHOICE_MODE_NONE.

Cuando el modo de acción termina, estoy llamando a este fragmento de código. clearChoices se asegura de que todos los elementos ya no se comprueben (internamente). La iteración sobre las vistas garantiza que todas las vistas actualmente visibles se restablezcan y ya no se comprueben.

mListView.clearChoices();

for (int i = 0; i < mListView.getChildCount(); i++) {
    ((Checkable) mListView.getChildAt(i)).setChecked(false);
}

mListView.setChoiceMode(ListView.CHOICE_MODE_NONE);
 19
Author: Knickedi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-10 21:47:12

Mirando el código fuente de ListView, la única manera de solucionar esto es establecer la ListView en CHOICE_MODE_NONE, luego reasignar el ListAdapter (que borra la lista de selección interna independientemente del modo de elección)

Es decir, en un ListFragment/ListActivity

getListView().setChoiceMode(ListView.CHOICE_MODE_NONE);
getListView().setAdapter(getListAdapter())
 18
Author: Migaloo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-21 14:03:01

Estaba teniendo este problema en API Level 17 y lo resolví haciendo:

listView.clearChoices();
listView.invalidateViews();
 4
Author: jpmcosta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-15 16:10:47

Para mí, parece que la respuesta aceptada no funciona para elementos invisibles, y no es necesario llamar

for (int i = 0; i < lv.getCount(); i++)
        lv.setItemChecked(i, false);

En su lugar, simplemente llame a

lv.requestLayout();

Para resolver completamente mi problema, llamo

lv.clearChoices();
lv.requestLayout();

En onDestroyActionMode()

Y llamar

lv.setItemChecked(position, false)

In onItemClick() when it's not in ActionMode

Sin embargo, no confirmé si la llamada setItemChecked() dará lugar a algunos problemas de rendimiento

 2
Author: darktiny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-04 03:04:24

Esto ha sido registrado como un bug de AOSP, pero marcado como obsoleto por cualquier razón.

Normalmente esperarías que esto funcionara:

getListView().clearChoices();
getListView().setChoiceMode(ListView.CHOICE_MODE_NONE);

Desafortunadamente no lo hace. Diferir el modo de elección de configuración a ninguno en el siguiente pase de diseño funcionaría:

getListView().clearChoices();
getListView().post(new Runnable() {
    @Override
    public void run() {
        getListView().setChoiceMode(ListView.CHOICE_MODE_NONE);
    }
});
 1
Author: hidro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-02 08:20:09

Había probado todos los enfoques discutidos anteriormente, pero ninguno de ellos funciona para mí. Finalmente, decido aplicar la siguiente solución. La idea clave es que,

Durante multimodo, en lugar de reutilizar la vista "cached", crearemos una vista completamente nueva. No eficiente, pero al menos "parcialmente" resolver mi problema.

Aquí está el código de mi personalizado ArrayAdapter

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    // Key to solve this problem. When we are in multimode, we will not reusing the cached view.
    View rowView = this.multimode ? null : convertView;

    if (rowView == null) {
        LayoutInflater inflater = activity.getLayoutInflater();
        rowView = inflater.inflate(R.layout.watchlist_row_layout, null);
        ViewHolder viewHolder = new ViewHolder();
        viewHolder.textView0 = (TextView) rowView.findViewById(R.id.text_view_0);
        viewHolder.textView1 = (TextView) rowView.findViewById(R.id.text_view_1);
        viewHolder.textView2 = (TextView) rowView.findViewById(R.id.text_view_2);
        rowView.setTag(viewHolder);
    }

Además, me siento más seguro de tener el siguiente código en ActionMode.Callback, aunque no estoy seguro de cómo ayuda mucho.

    @Override
    public void onDestroyActionMode(ActionMode mode) {
        MyFragment.this.myArrayAdapter.setMultimode(false);

        // http://stackoverflow.com/questions/9754170/listview-selection-remains-persistent-after-exiting-choice-mode
        // Using View.post is the key to solve the problem.
        final ListView listView = MyFragment.this.getListView();
        listView.clearChoices();
        for (int i = 0, ei = listView.getChildCount(); i < ei; i++) {
            listView.setItemChecked(i, false);
        }
        listView.post(new Runnable() {
            @Override
            public void run() {
                listView.setChoiceMode(ListView.CHOICE_MODE_NONE);
            }
        });
        actionMode = null;
    }

Nota al margen

Usando el par MultiChoiceModeListener con CHOICE_MODE_MULTIPLE_MODAL hará que este error desaparezca. Sin embargo, para el dispositivo por debajo del nivel de API 11 no podrá utilizar esta solución.

 0
Author: Cheok Yan Cheng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-25 07:24:17

Sé que esto ha sido respondido, pero las respuestas anteriores todavía me dieron problemas con las vistas en caché/recicladas que mantiene ListView, que no actualizaron su estado cuando se volvió a ver. Por lo tanto, la solución anterior cambia ligeramente a:

    lv.clearChoices();  

    ArrayList<View> list = new ArrayList<View>();
    lv.reclaimViews(list);
    for (View view : list) {
        ((Checkable) view).setChecked(false);
    }

    lv.setChoiceMode(lv.CHOICE_MODE_NONE);

Esto es mejor que usar getChildAt(i) porque ese método jusg le da las vistas actualmente visibles y no tiene en cuenta las vistas internas almacenadas en caché, que no son visibles.

 0
Author: anjosc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-22 19:14:15

He encontrado que los únicos dos métodos que funcionan aquí (API 19) son:

  • Restablecer el adaptador de lista, que no es deseable porque vuelve a la parte superior de la lista;
  • Establecer el modo de elección en CHOICE_MODE_NONE en un new Runnable

Si el modo de elección se cambia sin usar listView.post(new Runnable()), no funciona. ¿Alguien puede explicarme por qué es esto?

Disculpas por no comentar, no tengo reputación.

Gracias.

 0
Author: mdhvn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-03 10:25:17

No estoy seguro si esto es demasiado tarde solo quería compartir. Creé una intent en la misma página para que una vez que se capturan los datos en los que se hace clic, se recrea una página nueva sin persistencia en los que se hace clic.

 0
Author: Critical_Eye,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-24 10:39:58

No Es un error. Ese comportamiento es necesario para soportar múltiples HID para Android. Por lo tanto, para mostrar el estado de selección solo necesita establecer el modo de elección de la vista de lista y un fondo para soportar el estado seleccionado para el "diseño de elementos de lista", como:

android:background="?android:attr/activatedBackgroundIndicator"

PARA su información: http://android-developers.blogspot.mx/2008/12/touch-mode.html

 -2
Author: Daniel De León,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-19 18:52:00