I am developing a gallery-like Activity. Everything runs fine but there is a key functionality which is missing and I couldn't find a decent answer or explanation. What I need is to give the user the ability to select multiple items by long clicking on them.
Here is the desired result:
You can clearly see the selected pics and the options in the ActionBar.
My setup is this:
1.I have a GridView in my XML:
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/gridview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnWidth="90dp"
android:numColumns="auto_fit"
android:verticalSpacing="5dp"
android:horizontalSpacing="5dp"
android:stretchMode="columnWidth"
android:gravity="center"/>
2.It is attached to a class, which extends BaseAdapter and loads images using Picasso:
public class GalleryAdapter extends BaseAdapter {
Context mContext;
List<String> mDataset;
public GalleryAdapter(Context context, List<String> dataset) {
mContext = context;
mDataset = dataset;
}
@Override
public int getCount() {
return mDataset.size();
}
@Override
public Object getItem(int position) {
return mDataset.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if(convertView == null){
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(200,200));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(8,8,8,8);
} else {
imageView = (ImageView) convertView;
}
//TODO: REMOVE INTEGER.VALUEOFF. IT'S MADE FOR MOCK
Picasso.with(mContext).load(Integer.valueOf(mDataset.get(position))).fit().into(imageView);
return imageView;
}
}
3.It is attached to the Activity:
//Get images paths
List<String> data = getImagesPath(this);
List<String> sortedData = new ArrayList<>();
for(String file : data){
sortedData.add(0, file);
}
GalleryAdapter adapter = new GalleryAdapter(this, sortedData);
mGallery.setAdapter(adapter);
From now on the struggle begins:
I tried making my item in the GridView to implement Checkable:
public class CheckableItem extends LinearLayout implements Checkable{
private boolean mIsChecked = false;
private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };
public CheckableItem(Context context) {
super(context);
}
@Override
protected int[] onCreateDrawableState(int extraSpace) {
int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked())
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
return drawableState;
}
@Override
public void setChecked(boolean checked) {
mIsChecked = checked;
refreshDrawableState();
}
@Override
public boolean isChecked() {
return mIsChecked;
}
@Override
public void toggle() {
setChecked(!isChecked());
refreshDrawableState();
}
Then I load it in my XML and added .setChoiceMode(GridView.CHOICE_MODE_MULTIPLE)
to my GridView in the Activity. Nothing Happened.
Added MultiChoiceModeListener:
class MultiChoiceListener implements GridView.MultiChoiceModeListener{
@Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
int selectCount = mGallery.getCheckedItemCount();
switch (selectCount) {
case 1:
mode.setSubtitle("One item selected");
break;
default:
mode.setSubtitle("" + selectCount + " items selected");
break;
}
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.setTitle("Select Items");
mode.setSubtitle("One item selected");
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
}
}
Then added it to my gridView .setMultiChoiceModeListener(newMultiChoiceListener());
but still no results.
Can someone propose a way to achieve this item selecting behavior in GridView? I'd like to use the native Android API, no 3rd party libraries.
I think Checkable and the rest that I see in your code is a bit of an overkill...When I want to implement something like that I just add another field in the class of the object that is shown in the GridView/ListView which stores the checked state of the object. example:
class Image {
Bitmap bm;
boolean isChecked=false;
public Image(Bitmap bm){
this.bm=bm;
}
public boolean isChecked(){
return isChecked;
}
public void toggleChecked(){
isChecked = !isChecked;
}
}
and feed an ArrayList to the adapter. an in the getView method of the adapter I do something like this;
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(images.get(position).isChecked()){
//show the overlay view that suggests the item is selected
}
else{
//hide the overlay view
}
}
finally in the onItemClickListener of the ListView
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
images.get(position).toggleChecked();
listView.getAdapter().notifyDataSetChanged();
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With