I have a GridView with multiple items, but the items must be kept selected once the the onClickListener is called.How can i achive this?
I\'v already tried v.s
**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);
});
the views in the gridview
must be CheckBoxs
, in this way you can check and uncheck them .
The concept that you want to achieve is possible, but not like the way you are working now.
The best and easiest solution would be to keep track of the states of the clicked items and give them the correct layout inside the adapter. I have set up a little example:
Activity
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;
}
}
Main.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>
I think a better approach is to tell the GridView
that you wish to support selecting (checking) the items:
gridView.setChoiceMode(GridView.CHOICE_MODE_MULTIPLE);
and then make sure that items in GridView implement Checkable interface. That means that the items can be either Checkbox
, ToggleButton
and so on or you can add the Checkable
support yourself - for example make RelativeLayout checkable. (See the example below.)
In contrast to the other answer most of the work is taken care of by the GridView itself - no onClickListener
is needed. Instead of storing the state yourself, just call gridView.getCheckedItemIds()
or similar method.
To make RelativeLayout
(or anything) checkable make a subclass of it:
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);
}
}
Notice that the method onCreateDrawableState
updates the visual style. You don't have to do it this way, you can for example directly change the background in the setChange method.
Then use the CheckableRelativeLayout
as the top view for items in the 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>
And define how the background changes when the item is checked in 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>
I know the answer is a little bit old. But i think it's the easiest one of all. In your Adapter Class, add a variable containing the selected Item Position. Set transperency to all Images excluding the selected one in GetView method. In your click handler in main method, safe the selected ItemPosition. Notify the adapter that he has changed.
In your Adapter Class, add a variable containing the selected Item Position.
public class GridImageAdapter extends BaseAdapter {
public int selectedImage = 0;
Set transperency to all Images excluding the selected one in Adapter GetView method.
@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;
}
In your click handler in main method, safe the selected ItemPosition. Notify the adapter that he has changed
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();
}
});
Here's a terser version of Strix's answer (which I think is better than the accepted answer) when you don't need to reuse that code elsewhere. Instead of creating a new class and implementing Checked
, you can just create an anonymous class inside your Adapter.getView
method, overriding onCreateDrawableState
as in Strix's answer, but replace isChecked()
there with ((AbsListView)parent).isItemChecked(position)
. Here's the full code from my adapter that draws a border around checked thumbnails in a gallery:
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;
}
}