Pregunta

Estoy tratando de recrear lo que Google hizo con ListView en la aplicación Gmail. En particular, me gustaría que cada elemento de la lista incluya una casilla de verificación y dos vistas de text (una encima de la otra). Necesito oyentes para cuándo se verifica la casilla de verificación (o se hace clic) y cuando se hace clic en cualquier otro lugar del elemento de la lista. Por último, me gustaría que la barra de acción refleje que los elementos se seleccionan y proporcionan opciones como seleccionar todo, seleccionar ninguno, etc. (ver esta captura de pantalla).

enter image description here

Hasta ahora, aquí está el diseño que se me ocurrió.

<?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="match_parent"
    android:orientation="horizontal" >

    <CheckBox android:id="@+id/checkBox"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical|center_horizontal" />

    <LinearLayout android:id="@+id/linearLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="6dp"
        android:focusable="true"
        android:clickable="true" >

        <TextView android:id="@+id/titleTextView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="16sp" />

        <TextView android:id="@+id/dateTextView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="12sp" />

    </LinearLayout>

</LinearLayout>

Esto muestra todo correctamente, pero necesito consejos sobre cómo configurar los oyentes para las dos vistas (@+ID/Checkbox y @+id/linealLayout1). He mirado el LIST16 API Demo, pero están usando el diseño simple_list_item_activated_1 y no estoy seguro de cómo se ve el XML para eso. Como sugiere su código, creé un ModeCallback clase que implementa ListView.multicoicemodelistener Y configuré el modo de elección de ListView en Choice_Mode_Multiple_Modal, pero no sé cómo obtener la casilla de verificación en mi diseño para que funcione con esto.

¿Alguien ha copiado con éxito el comportamiento ListView de la aplicación Gmail? He buscado bastante y no se me ocurrió nada (a pesar de que varios otros hicieron preguntas similares, como éste - La mayoría de las respuestas apuntan a esta misma demostración de API).

Además, para el contexto, estoy cargando datos de una base de datos SQLite en la lista y he creado mi propio adaptador de cursor (que funciona bien). Tengo la sensación de que necesito configurar los oyentes en esta clase en los métodos newView () y BindView (), pero todo lo que he probado no ha funcionado.

¿Algunas ideas?

¿Fue útil?

Solución

El modo en la figura se llama modo de acción. Si está utilizando su vista de fila personalizada y su adaptador personalizado, no tiene que usar COME_MODE_MULTIPLE_MODAL para iniciar el modo de acción. Lo intenté una vez y fallé, y sospecho que se usa para el adaptador incorporado.

Para llamar al modo de acción por sí mismo en su código, llame al método de inicio del moderno en cualquier método del oyente de cualquiera de su vista, deje que sea casilla de verificación, textView o algo así. Luego pasa el Modecallback como parámetros en él y realiza cualquier operación que desee hacer en la clase Modecallback.

Sin embargo, no creo que este funcione en Android anterior a 3.0.

Aquí hay un breve ejemplo. Tengo una actividad de la lista expandible y quiero llamar al menú Modo de acción cuando el usuario verifica/desactiva la casilla de verificación, y aquí está mi método GetChildView en mi clase de adaptador personalizado:

public View getChildView(int groupPosition, int childPosition,
            boolean isLastChild, View convertView, ViewGroup parent) {

        if (convertView == null) {
            LayoutInflater inflater =  (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.childrow, null);
        }
        CheckBox cb = (CheckBox)convertView.findViewById(R.id.row_check);
        cb.setChecked(false);   // Initialize
        cb.setTag(groupPosition + "," + childPosition);
        cb.setFocusable(false); // To make the whole row selectable
        cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                String tag = (String)buttonView.getTag();
                String[] pos = tag.split(",");
                if (isChecked) {
                    if (mActionMode == null) mActionMode = startActionMode(mMultipleCallback);                      
                }
                else {
                    if (mActionMode != null) {  // Only operate when mActionMode is available

                        mActionMode.finish();
                        mActionMode = null;
                    }
                }
            }
        });

        TextView tvTop = (TextView)convertView.findViewById(R.id.row_text_top);
        TextView tvBottom = (TextView)convertView.findViewById(R.id.row_text_bottom);
        tvTop.setText(mChildren.get(groupPosition).get(childPosition));
        tvBottom.setText(mChildrenSize.get(groupPosition).get(childPosition));
        return convertView;
    }

Otros consejos

Esto funcionará en SDK 7 (Android 2.1) y superior. (junto con SherlockActionBar)

Totaly Mimic Gmail ListBox Experience.

Anulé OnTouchEvent para que presione en el lado de la esquina izquierda activará el modo de selección; Mutch mejor que intentar hacer clic en el pequeño cheackbox.

Anulé PerformitEmClick, por lo que presionar no en la izquierda actuará como una acción de prensa regular.

Anulé SetItemChecked para que actualice MactionMode según sea necesario.

public class SelectListView extends ListView {

    private SherlockFragmentActivity mActivity;
    ActionMode mActionMode;

      public SelectListView(Context context) {
    this( context, null, 0); 
}

public SelectListView(Context context, AttributeSet attrs) {   
    this( context, attrs, 0); 
}   


public SelectListView(Context context, AttributeSet attrs, int defStyle) {
    super( context, attrs, defStyle ); 
    setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
    mActivity = (SherlockFragmentActivity) context;
}

    @Override
    public boolean performItemClick(View view, int position, long id) {
        OnItemClickListener mOnItemClickListener = getOnItemClickListener();
        if (mOnItemClickListener != null) {
            playSoundEffect(SoundEffectConstants.CLICK);
            if (view != null)
                view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
            mOnItemClickListener.onItemClick(this, view, position, id);
            return true;
        }
        return false;
    }

    boolean mSelectionMode = false;
    int mStartPosition;

    @Override
    public boolean onTouchEvent(MotionEvent ev) {

        final int action = ev.getAction();
        final int x = (int) ev.getX();
        final int y = (int) ev.getY();

        if (action == MotionEvent.ACTION_DOWN && x < getWidth() / 7) {
            mSelectionMode = true;
            mStartPosition = pointToPosition(x, y);
        }
        if (!mSelectionMode)
            return super.onTouchEvent(ev);
        switch (action) {
        case MotionEvent.ACTION_DOWN:
            break;
        case MotionEvent.ACTION_MOVE:
            if (pointToPosition(x, y) != mStartPosition)
                mSelectionMode = false;
            break;
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
        default:
            mSelectionMode = false;
            int mItemPosition = pointToPosition(x, y);
            if (mStartPosition != ListView.INVALID_POSITION)
                setItemChecked(mItemPosition, !isItemChecked(mItemPosition));
        }

        return true;
    }

    @Override
    public void setItemChecked(int position, boolean value) {
        super.setItemChecked(position, value);
        // boolean r = getAdapter().hasStableIds();
        int checkedCount = getCheckItemIds().length;

        if (checkedCount == 0) {
            if (mActionMode != null)
                mActionMode.finish();
            return;
        }
        if (mActionMode == null)
            mActionMode = mActivity.startActionMode(new ModeCallback());

        mActionMode.setTitle(checkedCount + " selected");

    }

    class ModeCallback implements ActionMode.Callback {

        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {

            menu.add(getResources().getString(R.string.aBar_remove)).setIcon(R.drawable.ic_action_trash)
                    .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);

            return true;
        }

        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            return true;
        }

        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            Toast.makeText(mActivity, "Delted  items", Toast.LENGTH_SHORT).show();
            mode.finish();
            return true;
        }

        @Override
        public void onDestroyActionMode(ActionMode mode) {
            mActionMode = null;
            clearChecked();
        }

    }

    public void clearChecked() {
        SparseBooleanArray CItem = getCheckedItemPositions();
        for (int i = 0; i < CItem.size(); i++)
            if (CItem.valueAt(i))
                super.setItemChecked(CItem.keyAt(i), false);
    }

}

Puede usar cualquier adaptador de ListBox que necesite.

Si tiene una casilla de verificación en su lista_item_layout, debe extender su adaptador así:

ArrayAdapter<String> mAdapter = new ArrayAdapter<String>(this, R.layout.simple_list_item_multiple_choice,
            R.id.text1, Cheeses.sCheeseStrings) {

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View v = super.getView(position, convertView, parent);
            CheckBox checkBox = (CheckBox) v.findViewById(R.id.CheckBox);
            checkBox.setChecked(((ListView)parent).isItemChecked(position));
            return v;
        }

    };

No olvides usar Android: Background = "? Attr/ActivatedBackgroundIndicator" en tu lista_item_layout.xml

Además de la respuesta de ToCNBuff410, use el siguiente código para actualizar el recuento de elementos verificados

public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
    ++checkBoxCount;
 } else {
    --checkBoxCount;
 }
...

if (mActionMode != null) {
    mActionMode.setSubtitle(checkBoxCount + " item(s) selected.");
}

Puedo confirmar que el siguiente código no funcionaría en las casillas de verificación de ListViews personalizados. Sin embargo, Long Press seguiría funcionando:

listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener(new ModeCallback());

Seleccionar la casilla de verificación en ListView personalizado no activaría ActionMode. Solo ListViews incorporados, por ejemplo, extender ListActivity lo haría automáticamente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top