How to change background color for a specific row in ListView? (Android)

I spent several days trying to solve the problem that I have with ListViews on Android. I would like to implement a single select list using a ListView. So, I would like to have only one line with a predefined background color, and the rest with another highlighted color. The problem is that when I click on a specific line, this is another line that is highlighted, and not the one I clicked. I added a few messages to the log of what is happening, but everything is working fine. Here is my code:

public class TryListViewActivity extends Activity { protected static final int NO_SELECTED_COLOR = 0xFF191919; protected static final int SELECTED_COLOR = 0xFF3366CC; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ListView listView = new ListView(this); ArrayList<String> list = new ArrayList<String>(); list.add("Option 1"); list.add("Option 2"); list.add("Option 3"); list.add("Option 4"); list.add("Option 5"); list.add("Option 6"); list.add("Option 7"); list.add("Option 8"); list.add("Option 9"); list.add("Option 10"); list.add("Option 11"); list.add("Option 12"); list.add("Option 13"); list.add("Option 14"); list.add("Option 15"); ArrayAdapter<String> listAdapter = new ArrayAdapter<String>( this, R.layout.list_box_entry, list ); listView.setAdapter(listAdapter); listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); // Set the listener listView.setOnItemClickListener( new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Log.i( "Log", "[SingleSelectionListBox] Item clicked: position=" + position + ";id=" + id ); // First, set all rows to be unselected int counter = parent.getCount(); Log.i( "Log", "[SingleSelectionListBox] " + counter + " items found inside the parent" ); int children = parent.getChildCount(); Log.i( "Log", "[SingleSelectionListBox] " + children + " views found inside the parent" ); for(int i=0;i<children;i++) { Log.i( "Log", "[SingleSelectionListBox] Child " + i + " has message " + ((TextView)parent.getChildAt(i)).getText() ); } // Too inefficient but for now is OK for(int i=0;i<children;i++) parent.getChildAt(i) .setBackgroundColor(NO_SELECTED_COLOR); Log.i("Log", "[SingleSelectionListBox] First visible position: " + parent.getFirstVisiblePosition() ); // Set the background color TextView textView = (TextView)(parent.getChildAt( position-parent.getFirstVisiblePosition())); textView.setBackgroundColor(SELECTED_COLOR); Log.i( "Log", "[SingleSelectionListBox] Text inside the " + " View changing the color " + textView.getText() ); } } ); setContentView(listView); } } 

Inside the resources (res / layout) I inserted a file called list_text_entry.xml with the following contents

 <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center" android:textColor="#FFFFFF" android:padding="10dp" android:textSize="16sp"> </TextView> 

For example, if I clicked on the โ€œOption 11โ€ item, when the listView previously scrolled until the first line that I saw was โ€œOption 4โ€, the line โ€œOption 7โ€ would appear as the selected one, which would be the only blue background in background mode. Can someone explain what is happening to me here? I post below the posts that I have selected for the magazine.

 [SingleSelectionListBox] Item clicked: position=10;id=10 [SingleSelectionListBox] 15 items found inside the parent [SingleSelectionListBox] 11 views found inside the parent [SingleSelectionListBox] Child 0 has message Option 4 [SingleSelectionListBox] Child 1 has message Option 5 [SingleSelectionListBox] Child 2 has message Option 6 [SingleSelectionListBox] Child 3 has message Option 7 [SingleSelectionListBox] Child 4 has message Option 8 [SingleSelectionListBox] Child 5 has message Option 9 [SingleSelectionListBox] Child 6 has message Option 10 [SingleSelectionListBox] Child 7 has message Option 11 [SingleSelectionListBox] Child 8 has message Option 12 [SingleSelectionListBox] Child 9 has message Option 13 [SingleSelectionListBox] Child 10 has message Option 14 [SingleSelectionListBox] First visible position: 3 [SingleSelectionListBox] Text inside the View changing the color Option 11 

How can I guess that all the children inside the ViewGroup are ordered from top to bottom and even when I do this in code:

 TextView textView = (TextView)(parent.getChildAt( position-parent.getFirstVisiblePosition() )); textView.setBackgroundColor(SELECTED_COLOR); 

The message Option 11 appears, but option 7 actually selected. Is this a bug from Android?

+4
source share
7 answers

I used this code, it works well, you should try the following:

 listView.getChildAt(0).setBackgroundColor(Color.BLUE); 
+7
source

Yes, you should use as Dave said:

 view.setBackgroundColor(SELECTED_COLOR); 

and, perhaps,

 view.refreshDrawableState(); 

however, since Android's rewriting lists, it will repeat the color of your choice on every first item that doesn't appear on the screen. Therefore, if your screen size can display ten elements, except 11, 21, etc., it will also be displayed as selected when scrolling.

To avoid this, you need to create your own adapter. Then in getView you need to say the following:

 if (myActivity.selectedRow != position){ v.setBackgroundColor(Color.TRANSPARENT); } else { v.setBackgroundColor(SELECTED_COLOUR); } 

If selectedRow is public static int selectedRow in myActivity, this is the action that creates your list. There you store the line number that is selected when you click on the list.

+5
source

Thanks to Dave and ChristianB for your answers. I still don't know why Android does this, so the question still remains unresolved. However, I found a way to get what I need, create a custom adapter. I will give you the code if someone might need it.

 public class CustomAdapter extends ArrayAdapter<String> { protected static final int NO_SELECTED_COLOR = 0xFF191919; protected static final int SELECTED_COLOR = 0xFF3366CC; private ArrayList<String> items; private LayoutInflater mInflater; private int viewResourceId; private int selectedPosition; public CustomAdapter(Activity activity,int resourceId, ArrayList<String> list) { super(activity,resourceId,list); // Sets the layout inflater mInflater = (LayoutInflater)activity .getSystemService(Context.LAYOUT_INFLATER_SERVICE); // Set a copy of the layout to inflate viewResourceId = resourceId; // Set a copy of the list items = list; } @Override public View getView(int position, View convertView, ViewGroup parent) { TextView tv = (TextView)convertView; if (tv == null) { tv = (TextView)mInflater.inflate(viewResourceId, null); } tv.setText(items.get(position)); // Change the background color if (position==selectedPosition) tv.setBackgroundColor(SELECTED_COLOR); else tv.setBackgroundColor(NO_SELECTED_COLOR); return tv; } public void setSelected(int position) { selectedPosition = position; } } 

So, in ListView initialization, I just need to put this listener:

 listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { ((CustomAdapter)listAdapter).setSelected(position); listView.invalidate(); } }); 

This is not an effective solution due to the fact that I am expanding from an ArrayAdapter, which, presumably, should have a copy of all the data provided. This way, I use a lot more memory than necessary, and in case the list gets very large, I could have memory problems. So, if someone knows the best solution, write!

+5
source

I believe this is due to the way ListViews number and reuse strings. Therefore, instead of using parent.getChildAt(i) to get the row you want to process, use the View object passed to onItemClick itself.

 view.setBackgroundColor(SELECTED_COLOR); 
0
source

listview.setOnItemClickListener (new AdapterView.OnItemClickListener () {

  @Override public void onItemClick(AdapterView<?> parent, final View view, int position, long id) { View v; int count = parent.getChildCount(); v =parent.getChildAt(position); parent.requestChildFocus(v, view); v.setBackground(res.getDrawable(R.drawable.transparent_button)); for (int i=0; i<count; i++) { if (i!= position) { v = parent.getChildAt(i);t v.setBackground(res.getDrawable(R.drawable.not_clicked)); } } } }); 

Basically, create two drawing options - transparent, and the other the desired color. Request focus at the pressed position (int position as defined) and change the color of the specified line. Then go through the parent list and change all the other lines accordingly. This is because the user clicks on listview several times.

0
source
  @Override public View getView(int position, View convertView, ViewGroup parent) { LayoutInflater inflater=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View itemView = inflater.inflate(R.layout.verselayout, parent, false); txttitle = (TextView) itemView.findViewById(R.id.Versetxt); if (position%2 == 0) { txttitle.setTextColor(Color.parseColor("#FFFFFF")); } else { txttitle.setTextColor(Color.parseColor("#FFFF00")); } return itemView; } 
0
source

try it,

 OnItemClickListener onitemclick = new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapter, View arg1, int position, long id) { selectedItem= position; adapter.notifyDataSetChanged(); } }; 

override the getView () method of your adapter:

  @Override public View getView(int position, View convertView, ViewGroup parent) { final View view = View.inflate(context, R.layout.item_list, null); if (position == selectedItem) { // set your color } return view; } 
0
source

Source: https://habr.com/ru/post/1334759/


All Articles