How do I retain selected item highlighting on gridview when numColumns changes?
Asked Answered
L

2

8

I have an ActionBarActivity with a GridView.

The GridView has 2 columns in portrait and 3 columns in landscape.

When I select items in portrait (starting my ActionMode) and then rotate the device, the selected item highlighting shifts one item to the left. For example, if I select the second item and rotate, the first item will be highlighted. If I select the first item and rotate, no items are highlighted.

The actual selection in the code is correct, just the highlighting is wrong.

I notice it does not do this if I keep the numColumns the same for portrait and landscape.

I believe this issue started occurring after I changed my activity to an ActionBarActivity so it could be a bug..

Anyone know why or how to fix it?

Launder answered 4/1, 2015 at 19:17 Comment(4)
how are you defining the column no for portrait and landscape mode?Proposition
@HardikChauhan I am using the gridview's NumColumns attribute in the layout XML and the number is a dimen value as 3 in my -layout-land resource directory and 2 in the default layout resource directory.Launder
ok i find the solution and let you know.Proposition
ho do you show the highlighting? I suppose you use a state selector background. Do you use "activated" state? Do you set the state manually when clicking an item?Goldthread
B
5

I had a similar scenario and ended up solving the issue be creating a custom grid item with a boolean field to keep track of whether the item is selected or not and then highlighting the item appropriately through the custom adapter. Below is a rough outline of what I did:

(1) I created a custom grid item with a boolean field, which we will call selectedStatus for simplicity's sake. I also added the corresponding methods to my grid item class to get the selected status:

public boolean getSelectedStatus ()
{
    return selectedStatus;
}

public void setSelectedStatus (boolean paramSelectedStatus)
{
    this.selectedStatus = paramSelectedStatus;
}

(2) I then created a custom Adapter that extends BaseAdapter to handle the custom grid object I created. In this Adapter I check the if the selected status of the grid object is true or false and highlight the item accordingly, shown below:

@Override
public View getView (final int position, View convertView, ViewGroup parent)
{

    // rest of getView() code...

    if (!yourGridObject.getSelectedStatus())
    {
        convertView.setBackgroundColor(Color.TRANSPARENT);
    }
    else
    {
        convertView.setBackgroundColor(Color.LTGRAY);
    }

    // rest of getView() code...

    return convertView;
}

(3) Lastly, you add the onItemClickListener to set the selected status and the background color of the grid items when they are selected (clicked):

yourGridView.setOnItemClickListener(new OnItemClickListener()
{
    @Override
    public void onItemClick(AdapterView<?> parent, View view, 
            int position, long id)
    {
        YourGridObject yourGridObject = (YourGridObject) parent.getItemAtPosition(position);
        if (!yourGridObject.getSelected())
        {
            view.setBackgroundColor(Color.LTGRAY);
            yourGridObject.setSelected(true);
        }
        else
        {
            view.setBackgroundColor(Color.TRANSPARENT);
            yourGridObject.setSelected(false);
        }
    }
});

Implementing selection this way ensures that the highlighting (selection) of the grid items will not change when the number of columns and rows swap since the selection status is contained within the grid objects themselves.

Billet answered 16/1, 2015 at 23:5 Comment(0)
V
3

You don't need to manually handle selection of items as suggested by Willis. Android fully supports what you are asking. I will assume you are using an ArrayAdapter however this answer would apply to all adapters. Note some adapters (like CursorAdapter) won't suffer from your posted problem and don't require the following solution because it's already doing it internally.

The problem is solved in two parts. One, the adapter must enable stable Ids. Two, your adapter must actually return stable ids. You will need to extend the ArrayAdapter or which ever adapter you are using. Then ensure you have defined the following methods as shown below.

private class MyAdapter extends ArrayAdapter<YourObjects> {
    @Override
    public boolean hasStableIds() {
        return true;
    }

    @Override
    public long getItemId(int position) {
        //Return a unique and stable id for the given position
        //While unique, Returning the position number does not count as stable.
        //For example:
        return getItem(position).methodThatReturnsUniqueValue();
    }
}

Most adapters do not enable hasStableIds. It's primarily only used when enabling a choiceMode. Which I assume you are doing here. By returning true, you are essentially telling Android to keep track of activated (highlighted) items based on their ID value instead of their position number.

Even with stable Ids enabled, you have to actually return an ID that is unique and stable across positional changes. Since most adapters do NOT enable stable IDs, they usually only return the position number as the stable id. Technically, if an item's position never changes over time then the position number "could" be used as the stable id. However, the safest way to return a stable/unique ID is to have one assigned to the class object being stored in the adapter and pull from that.

Vegetative answered 20/1, 2015 at 12:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.