I have a GridView
with a bunch of icons and I need to select one. And by select I mean:
- I need the drawable id to store into a database (so I can access it later)
- I need to draw some kind of visual cue on the grid to let the user know which icon is currently selected
I found th开发者_如何学编程is:
http://groups.google.com/group/android-developers/browse_thread/thread/f08a58167dbaa8c8So I guess setSelection
is out of the picture and I can't use it to select the icon itself nor draw the visual cue. I know the grid item position in the onItemClickListener
and I can save it as a private class variable. My biggest problem is drawing that visual cue.
How can I achieve that? How can I draw a visual cue on the clicked item and if the user clicks different items, to "undraw" that visual cue and redraw it in the new item?
After tackling with this for a couple of hours I think I finally found the solution I was looking for. Although the answers are barely related, the initial edits on Ian solution helped me find this solution :)
I'm not going to explain everything I did, I think it's pretty self explanatory. Just a few remarks:
First I tried
view.Invalidate()
andview.postInvalidate()
instead oficonAdapter.notifyDataSetChanged()
but neither worked. The documentation stated that the invalidate methods only "asked" to redraw the view "when possible".I was looking for a simpler solution than to merge two drawables. For instance, draw the icon on the
ImageView
background and the visual cue as the image. For some strange reason, the visual cue started to show randomly all over the other icons when theGridView
was scrolled. I don't understand why, but the idea of a visual cue on top of a background image makes perfect sense to me andImageView
allows that, no need for that extra merge method. However, I couldn't make it work without it...
MyActivity.java
public class MyActivity extends Activity {
private GridView mGridViewIcon;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mGridViewIcon = (GridView)findViewById(R.id.gridview_icon);
mGridViewIcon.setAdapter(new IconAdapter(this));
mGridViewIcon.setOnItemClickListener(new GridView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
IconAdapter iconAdapter = (IconAdapter)parent.getAdapter();
iconAdapter.setSelectedItemPosition(position);
iconAdapter.notifyDataSetChanged();
}
});
}
}
IconAdapter.java
public class IconAdapter extends BaseAdapter {
private int mSelectedPosition;
private Integer[] mThumbIds;
private int mIconSize;
private Context mContext;
public IconAdapter(Context context) {
mThumbIds = AppHelper.ICON_SET.keySet().iterator().next();
mIconSize = context.getResources().getDimensionPixelSize(R.dimen.default_icon_size);
mContext = context;
}
@Override
public int getCount() {
return mThumbIds.length;
}
@Override
public Object getItem(int position) {
return mContext.getResources().getDrawable(mThumbIds[position]);
}
@Override
public long getItemId(int position) {
return mThumbIds[position];
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if(convertView == null) {
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(mIconSize, mIconSize));
} else {
imageView = (ImageView)convertView;
}
if(mSelectedPosition == position) {
imageView.setImageDrawable(mergeDrawableLayers(mThumbIds[position],
R.drawable.ic_note_selected_mark));
} else {
imageView.setImageResource(mThumbIds[position]);
}
return imageView;
}
public void setSelectedItemPosition(int position) {
mSelectedPosition = position;
}
private Drawable mergeDrawableLayers(int background, int overlay) {
Drawable[] drawableLayers = new Drawable[2];
drawableLayers[0] = mContext.getResources().getDrawable(background);
drawableLayers[1] = mContext.getResources().getDrawable(overlay);
return new LayerDrawable(drawableLayers);
}
}
I believe, that if you want some kind of selection cue, you need a focusable object. However, with a focusable object (such as a Button), attaching OnItemClickListener to the GridView does not work (if i remember correctly). Rather, you must individually attach an OnClickListener to each item at getView() in the adapter.
Adapter:
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
Button button;
if (convertView == null) { // if it's not recycled, initialize some attributes
button = new Button(mContext);
// set layout params (make sure its GridView.layoutParams)
// and other stuff
}
else {
button = (Button) convertView;
}
button.setBackgroundResource(mThumbIds[position]); // mThumbIds hold Resource Ids
button.setOnClickListener(new OnClickListener() {
onClick(View v) {
// store directly to database here, or send it with the activity with sharedPreferences (below)
// We need an Editor object to make preference changes.
// All objects are from android.context.Context
SharedPreferences settings = getSharedPreferences("MY_PREFERENCE", 0);
SharedPreferences.Editor editor = settings.edit();
editor.putInt("button_id", mThumbIds[position]);
// Commit the edits!
editor.commit();
}
});
return button;
}
}
On Activity Side, save button onClickListener:
onClick(View v) {
// Restore preferences
SharedPreferences settings = getSharedPreferences("MY_PREFERENCE", 0);
int id = settings.getInt("button_id", -1);
// now safe all stuff to database
}
There may be details missing because a Button is focusable, but i think this should do. Also , you will achieve the selection by using a .xml defined selector resource. That, however, should be addressed in a separate question.
Edit 1: Actually now that i think about it, i'm not sure if a drawable .xml (the selector) can have an ID. I'll have to implement this at home later on and try it.
Edit 2: I added the sharedPreference part
Edit 3: Added activity side querying of sharedPreference.
精彩评论