2
votes

I have a gridview that contains text and images. When a user touches a cell in the grid, it changes color to show that it is selected and when selected again it returns to the default color to show that it is no longer selected. Any number of cells can be selected. The problem is when a user has to scroll through the grid to see all of the icons the selected icons sometimes become unselected and select "random" other cells. I suspect this is related to the gridview being recycled but am unsure how to address this.

public class Onboarding extends Activity {
GridView grid;
ArrayList selectedCategories = new ArrayList<>();
CustomGrid adapter;
String[] dummyString = {
        "item 1",
        "item 2",
        "item 3",
        "item 4",
        "item 5",
        "item 6",
        "item 7",
        "item 8",
        "item 9",
        "item 10",
        "item 11",
        "item 12",
        "item 13",
        "item 14",
        "item 15",
        "item 16",
        "item 17",
        "item 18",
        "item 19"
};
int[] imageId = {
        R.drawable.1,
        R.drawable.2,
        R.drawable.3,
        R.drawable.4,
        R.drawable.5,
        R.drawable.6,
        R.drawable.7,
        R.drawable.8,
        R.drawable.9,
        R.drawable.10,
        R.drawable.11,
        R.drawable.12,
        R.drawable.13,
        R.drawable.14,
        R.drawable.15,
        R.drawable.16,
        R.drawable.17,
        R.drawable.18,
        R.drawable.19
};


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_onboarding);
    getWindow().setSoftInputMode(
            WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN
    ); //makes sure keyboard is hidden on this view as it is not needed
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);

    grid = (GridView) findViewById(R.id.grid);

    //deals with settings the number of Columns
    DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();
    double dpWidth = displayMetrics.widthPixels / displayMetrics.density;
    if (dpWidth <= 400) {
        grid.setNumColumns(2);
    } else if (dpWidth > 400 && dpWidth < 500) {
        grid.setNumColumns(3);
    } else if (dpWidth >= 500 && dpWidth < 550) {
        grid.setNumColumns(4);
    } else {
        grid.setNumColumns(5);
    }

    adapter = new CustomGrid(Onboarding.this, dummyString, imageId);
    grid.setAdapter(adapter);
    grid.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view,
                                int position, long id) {
            //the position is the actual position that is pressed. but the getChildAt returns gets the relative position, ie what's being drawn
            //on the grid.
            //to fix this, the first visible position is obtained and the difference is subtracted
            int firstPos = grid.getFirstVisiblePosition();
            View tv = grid.getChildAt(position - firstPos);
            Toast.makeText(Onboarding.this, "You Clicked at position" + position + " " + dummyString[+position] + "firstPos " + firstPos, Toast.LENGTH_SHORT).show(); //debug

            if (tv == null) { //this shouldn't/doesn't happen
                Log.e("OnBoarding.java", "Issue with null view at line " + Thread.currentThread().getStackTrace()[2].getLineNumber() +
                        "grid is having a problem");
                return;
            }

            if (selectedCategories.contains(dummyString[+position]) == false) {//add the item if it doesn't exist
                selectedCategories.add(dummyString[+position]);
                tv.setBackgroundColor(Color.parseColor("#FFE5CD"));
            } else { //remove the item if it already exists, as the user is removing it by touching it again
                selectedCategories.remove(dummyString[+position]);
                tv.setBackgroundColor(Color.parseColor("#EEEEEE"));
            }
        }
    });

}

}

public class CustomGrid extends BaseAdapter {
private Context mContext;
private final String[] genreString;
private final int[] Imageid;

public CustomGrid(Context c, String[] genreString, int[] Imageid) {
    mContext = c;
    this.Imageid = Imageid;
    this.genreString = genreString;
}

@Override
public int getCount() {
    return genreString.length;
}

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

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

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View grid;
    LayoutInflater inflater = (LayoutInflater) mContext
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    TextView textView;
    ImageView imageView;
    if (convertView == null) {
        grid = inflater.inflate(R.layout.grid_single, null);
    } else {
        grid = convertView;
    }
    textView  = (TextView) grid.findViewById(R.id.grid_text);
    imageView = (ImageView) grid.findViewById(R.id.grid_image);
    textView.setText(genreString[position]);
    imageView.setImageResource(Imageid[position]);

    return grid;
}

}

4

4 Answers

1
votes

Steps to change a Color on click gridview item

1) create a selector in side drawable like

<item android:drawable="@color/blue" android:state_pressed="true" />
<item android:drawable="@color/blue" android:state_selected="true" />
<item android:drawable="@color/white" />

2) set background to item layout of grid view like

android:background="@drawable/grid_color_selector"

hope it will work for you.

1
votes

What I ended up doing to fix this was using a scroll listener on the gridview.

        grid.setOnScrollListener(new AbsListView.OnScrollListener() {
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            //Log.d("Onboarding 7331", "onScroll: onScroll " + firstVisibleItem + " " + selectedPositions.toString());
            for (int i = 0; i < totalItemCount; i++) {
                View tv = grid.getChildAt(i - firstVisibleItem);
                if (tv == null) {
                    continue;
                }
                if (selectedPositions.contains(Integer.toString(i))) {
                    tv.setBackgroundColor(Color.parseColor("#FFE5CD"));
                } else {
                    tv.setBackgroundColor(Color.parseColor("#EEEEEE"));
                }
            }
        }

        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            //     Log.d("Onboarding 7331", "onScroll: state changed "+selectedPositions.toString());
        }
    });
0
votes

Just Use this Hope this will help

     gridview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View v,
                                int position, long id) {
            View currentPosition = gridview.getChildAt(position);
            if (previousSelectedPosition != -1) {
                View previousPos = gridview.getChildAt(previousSelectedPosition);
                previousPos.setBackgroundResource(R.drawable.calendar_cell);
            }
            currentPosition.setBackgroundResource(R.drawable.calendar_cel_selectl);
            previousSelectedPosition = position;
        }
    });
0
votes

Inside the XML file of GridView add this element android:listSelector="@drawable/grid_view_selected" and the code for drawable could be like this:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#E80335" />
    <corners
        android:bottomRightRadius="5dp"
        android:bottomLeftRadius="5dp"
        android:topLeftRadius="5dp"
        android:topRightRadius="5dp" />
    <stroke
        android:color="@color/material_grey_600"
        android:width="2dp" />
</shape>

That's It. No need to add or do any override methods to change color of cell of gridview.