I have spent some days trying to solve a problem I have with ListViews on Android. I would like to implement a single selection list box using a ListView. So, I would like t
try this,
OnItemClickListener onitemclick = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapter, View arg1, int position, long id) {
selectedItem= position;
adapter.notifyDataSetChanged();
}
};
override 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;
}
Yes you should use as Dave said:
view.setBackgroundColor(SELECTED_COLOR);
and perhaps
view.refreshDrawableState();
however because Android recycle lists, it will repeat your selected colour on every first item which is not shown on the screen. So if your screen size can show ten items than 11th, 21nd etc will be also shown as selected when you scroll.
To avoid this you have to create a custom adapter. Then in getView you need to say this:
if (myActivity.selectedRow != position){
v.setBackgroundColor(Color.TRANSPARENT);
} else {
v.setBackgroundColor(SELECTED_COLOUR);
}
Where selectedRow is a public static int selectedRow
within myActivity, the activity which creates your list. There you store the row number which is selected when clicking the list.
Thanks Dave and ChristianB for your answers. I still do not know why Android does it, so the question is still unresolved. However, I found a way to get what I needed creating a custom Adapter. I will give you the code in case someone could 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 the 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 efficient solution due to I am extending from ArrayAdapter which is suppose to have a copy of all data provided. Thus, I am using much more memory than needed and in case the list becomes very large I could have memory trouble. So, if someone knows a better solution, please post!
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 drawables - one that is transparent, and another that is the desired color. Request focus at the clicked position (int position as defined) and change the color of said row. Then walk through the parent listview, and change all other rows accordingly. This accounts for when a user clicks on the listview multiple times.
I have used this code it works nice you should try this:
listView.getChildAt(0).setBackgroundColor(Color.BLUE);
I believe this is due to the way ListViews number and re-use rows. So, rather than using parent.getChildAt(i)
to get the row you wish to manipulate, use the View
object passed to onItemClick
itself.
view.setBackgroundColor(SELECTED_COLOR);