Android gridview mantener el elemento seleccionado

Tengo un GridView con varios elementos, pero los elementos deben mantenerse seleccionados una vez que se llama onClickListener. ¿Cómo puedo lograr esto?

ya lo he intentado v.setSelected(true) pero no parece funcionar.

gridview.setOnItemClickListener(new OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View v,
                int position, long id) {
            // Toast.makeText(Project.this, "Red" + position,
            // Toast.LENGTH_SHORT).show(); //position = al catelea element
            v.setPressed(true);
            if (bp == 2) {
                if (position == 0) {
                Square.setSex(R.drawable.girl_body2v);
                Square2.setHair(R.drawable.girl_hair_01v);
                SquareAccesories.setAcc(R.drawable.girl_accessories_01v);
                SquareEyes.setEyes(R.drawable.eyes_1v);
                SquareLips.setLips(R.drawable.lip_1v);
                Square3.setDress(R.drawable.girl_tops_01v);
                SquareShoes.setShoes(R.drawable.girl_shoes_01v);
                SquarePants.setPants(R.drawable.girl_bottom_01v);
                setS(2);

Esta es una pequeña parte del código para onClickListener porque tengo muchos casos.

preguntado el 04 de julio de 12 a las 10:07

¿Puede proporcionarnos algún código? -

6 Respuestas

Creo que un mejor enfoque es decirle al GridView que desea apoyar seleccionando (marcando) los elementos:

gridView.setChoiceMode(GridView.CHOICE_MODE_MULTIPLE);

y luego asegúrate de que elementos en GridView implementar Comprobable interfaz.. Eso significa que los elementos pueden ser Checkbox, ToggleButton y así sucesivamente o puede agregar el Checkable manténgase a sí mismo, por ejemplo, haga que RelativeLayout sea verificable. (Vea el ejemplo a continuación).

En contraste con la otra respuesta, la mayor parte del trabajo está a cargo del propio GridView, no onClickListener se necesita En lugar de almacenar el estado usted mismo, simplemente llame gridView.getCheckedItemIds() o método similar.


Para hacer RelativeLayout (o cualquier cosa) verificable hacer una subclase de la misma:

public class CheckableRelativeLayout extends RelativeLayout implements Checkable {
    private boolean checked = false;
    private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };

    public CheckableRelativeLayout(Context context) {
        super(context);
    }

    public CheckableRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CheckableRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected int[] onCreateDrawableState(int extraSpace) {
         final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
         if (isChecked())
             mergeDrawableStates(drawableState, CHECKED_STATE_SET);
         return drawableState;
    }

    @Override
    public boolean isChecked() {
        return checked;
    }

    @Override
    public void setChecked(boolean _checked) {
        checked = _checked;
        refreshDrawableState();
    }

    @Override
    public void toggle() {
        setChecked(!checked);
    }

}

Note que el método onCreateDrawableState actualiza el estilo visual. No tiene que hacerlo de esta manera, puede, por ejemplo, cambiar directamente el fondo en el método setChange.

Entonces usa el CheckableRelativeLayout como la vista superior de los elementos en GridView:

<foo.bar.CheckableRelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="@drawable/my_awesome_background"
    ... more stuff
    >
        ...  content of the relative layout
</com.test.CheckableRelativeLayout>

Y defina cómo cambia el fondo cuando se registra el elemento res/drawable/my_awesome_background.xml:

<selector xmlns:android="http://schemas.android.com/apk/res/android" > 
     <item android:state_checked="true" >
        <!-- This applies when the item is checked. -->
         <shape android:shape="rectangle"  >
             <solid android:color="#A8DFF4" />
         </shape>
     </item>

    <item>
        <!-- This applies when the item is not checked. -->
        <shape android:shape="rectangle"  >
             <solid android:color="#EFEFEF" />
         </shape>
     </item>
</selector>

Respondido el 30 de junio de 13 a las 12:06

¿Cómo aplicaría su código a un GridView que contiene imágenes? - AFD

Crear una nueva clase y heredar ImageView en lugar de RelativeLayout. Puede aplicar este código a cualquier 'Vista' que desee, pero asegúrese de que el estilo funcione. Quizás una animación sea más apropiada para las imágenes, en lugar de cambiar el color de fondo. - Strix

No funciona con StickyHeadersGridView... Y es una gran biblioteca y vale la pena hacerlo manualmente. Pero esa es la mejor práctica =) - Renán Franca

¿Cómo escucho el evento oncheck del diseño? - gaara87

Las vistas se destruyen y se vuelven a crear cuando se desplaza una vista de cuadrícula, por lo que este enfoque no funcionará... Cuando se desplaza la cuadrícula, el elemento previamente seleccionado puede destruirse/reciclarse y la verificación aparecerá en subvistas inesperadas de esta cuadrícula. En mi caso en Android 2.3.3 lo vi en libertad. - Southerton

El concepto que desea lograr es posible, pero no como la forma en que está trabajando ahora.

La solución mejor y más fácil sería hacer un seguimiento de los estados de los elementos en los que se hizo clic y darles el diseño correcto dentro del adaptador. He puesto un pequeño ejemplo:

Actividad

public class StackOverFlowActivity extends Activity {
    GridView gridView;
    MyCustomAdapter myAdapter;
    ArrayList<GridObject> myObjects;

    static final String[] numbers = new String[] { "A", "B", "C", "D", "E",
            "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
            "S", "T", "U", "V", "W", "X", "Y", "Z" };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        myObjects = new ArrayList<GridObject>();
        for (String s : numbers) {
            myObjects.add(new GridObject(s, 0));
        }

        gridView = (GridView) findViewById(R.id.gridView1);

        myAdapter = new MyCustomAdapter(this);

        gridView.setAdapter(myAdapter);
        gridView.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> arg0, View v, int position, long arg3) {
                myObjects.get(position).setState(1);
                myAdapter.notifyDataSetChanged();
            }
        });
    }

    static class ViewHolder {
        TextView text;
    }

    private class MyCustomAdapter extends BaseAdapter  {

        private LayoutInflater mInflater;

        public MyCustomAdapter(Context context) {
            mInflater = LayoutInflater.from(context);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            GridObject object = myObjects.get(position);
            ViewHolder holder;

            if (convertView == null) {
                convertView = mInflater.inflate(R.layout.list_item_icon_text, null);
                holder = new ViewHolder();
                holder.text = (TextView) convertView.findViewById(R.id.text);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }

            holder.text.setText(object.getName());

            if (object.getState() == 1) {
                holder.text.setBackgroundColor(Color.GREEN);
            } else {
                holder.text.setBackgroundColor(Color.BLUE);
            }
            return convertView;
        }

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

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

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

GridObject

public class GridObject {

    private String name;
    private int state;

    public GridObject(String name, int state) {
        super();
        this.name = name;
        this.state = state;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }   
}

Principal.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <GridView
        android:id="@+id/gridView1"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:columnWidth="50dp"
        android:gravity="center"
        android:numColumns="auto_fit"
        android:stretchMode="columnWidth" >
    </GridView>

</LinearLayout>

list_item_icon_text

<?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="vertical" >

    <TextView
        android:id="@+id/text"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</LinearLayout>

Respondido 04 Jul 12, 12:07

Es una mala idea almacenar el estado checked en una clase de negocios (modelo). La vista que muestra los datos debería encargarse de ello. Además, cambiar el fondo en el adaptador y onClickListener parece un truco. GridView puede hacer la mayor parte del trabajo por usted, ¿por qué no dejarlo? (Ver mi respuesta.) - Strix

Pero esto funcionará en el desplazamiento de las vistas de cuadrícula/lista, mientras que el almacenamiento del estado marcado en la vista no lo hará, porque las vistas dentro de las cuadrículas en Android se reciclan cuando se produce el desplazamiento. - Southerton

Aquí hay una versión más breve de la respuesta de Strix (que creo que es mejor que la respuesta aceptada) cuando no necesita reutilizar ese código en otro lugar. En lugar de crear una nueva clase e implementar Checked, puede simplemente crear una clase anónima dentro de su Adapter.getView método, primordial onCreateDrawableState como en la respuesta de Strix, pero reemplaza isChecked() allí con ((AbsListView)parent).isItemChecked(position). Aquí está el código completo de mi adaptador que dibuja un borde alrededor de las miniaturas marcadas en una galería:

public class ImageAdapter extends BaseAdapter {
    private final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };
    public int getCount() {return images.size();}
    public Object getItem(int position) {return images.get(position);}
    public long getItemId(int position) {return position;}

    public View getView(final int position, final View convertView, final ViewGroup parent) {
        final ImageView imageView = new ImageView(getApplicationContext()) {
            @Override public int[] onCreateDrawableState(int extraSpace) {
                final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
                if (((AbsListView)parent).isItemChecked(position)) {
                    mergeDrawableStates(drawableState, CHECKED_STATE_SET);
                }
                return drawableState;
            }
        };
        imageView.setBackground(getResources().getDrawable(R.drawable.my_awesome_background));
        imageView.setScaleType(ImageView.ScaleType.CENTER);
        final byte[] buffer = images.get(position);
        final Bitmap bmp = BitmapFactory.decodeByteArray(buffer, 0, buffer.length);
        imageView.setImageBitmap(bmp);
        return imageView;
    }
}

Respondido 25 Oct 13, 22:10

Sé que la respuesta es un poco vieja. Pero creo que es el más fácil de todos. En su clase de adaptador, agregue una variable que contenga la posición del elemento seleccionado. Configure la transparencia de todas las imágenes excepto la seleccionada en el método GetView. En su controlador de clics en el método principal, proteja el ItemPosition seleccionado. Notifique al adaptador que ha cambiado.

En su clase de adaptador, agregue una variable que contenga la posición del elemento seleccionado.

public class GridImageAdapter extends BaseAdapter {
       public int selectedImage = 0;

Configure la transparencia de todas las imágenes excepto la seleccionada en el método Adapter GetView.

@Override
public View getView(final int position, View convertView, final ViewGroup parent) {
    int[] images = { R.drawable.walk, R.drawable.run, R.drawable.jump }

    ImageView imageView = new ImageView(mContext);
    if (position < imgMapper.length) {

        imageView.setImageResource(images[position]);

        if (position != selectedImage) {
            imageView.setImageAlpha(50);
        }
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        imageView.setLayoutParams(new GridView.LayoutParams(150, 150));
    };

    return imageView;
}

En su controlador de clics en el método principal, proteja el ItemPosition seleccionado. Notificar al adaptador que ha cambiado

   myGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
            GridImageAdapter myAdapter = (GridImageAdapter) myGridView.getAdapter();
            myAdapter.selectedImage = position;
            myAdapter.notifyDataSetChanged();
        }
    });

Respondido 20 Oct 15, 21:10

Además, puede hacer muchas otras cosas con la imagen seleccionada, por ejemplo, si desea colorearla, simplemente use: imageView.setBackgroundColor(Color.BLUE); - maníaco

+1 Gran enfoque, simple y agradable. Sin embargo, prefiero cambiar selectedImage y notificar el cambio directamente dentro del adaptador, pero lo que es más importante, elegí crear la vista de imagen una vez en la primera llamada de getView y reutilizarla para otras imágenes (como patrón ViewHolder). La ventaja es que el adaptador no necesita crear múltiples vistas para cada elemento. Se adapta perfectamente a tu respuesta. - Blo

las vistas en el gridview debe ser CheckBoxs, de esta forma podrás marcarlos y desmarcarlos .

Respondido 04 Jul 12, 10:07

¿Cómo puedo agregar casillas de verificación a gridview? - chan chow

Ver youtube.com/watch?v=wDBM6wVEO70 para empezar ListView y GridView funcionan de la misma manera. - Strix

**You can add tag and check for tag**


 gv.setOnItemClickListener((adapterView, view, i, l) -> {

                int f = gv.getCheckedItemPosition();

                if(view.getTag()=="selected")
                {
                    view.setTag("notselected");
                    String clickedText = gv.getItemAtPosition(i).toString();
                    filterKeywords.remove(clickedText);
                    view.setBackgroundColor(Color.WHITE);
                }
                else
                {
                    view.setTag("selected");
                    String clickedText = gv.getItemAtPosition(i).toString();
                    filterKeywords.add(clickedText);
                    view.setBackgroundColor(Color.GREEN);

                }

                System.out.println("KEYWORDS"+filterKeywords);


            });

Respondido 08 ago 18, 09:08

¡Creemos que te podría gustar ¿Cómo comparo cadenas en Java? - dima kozhevin

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.