Android's selector for selected item does not work - android

I have a listview, where I want to highlight selected items in a custom way. I'm setting every item properties in the adapter's getView method, including itemView.setSelected(true).
The main layout defines the listview in the following way:
<ListView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:choiceMode="multipleChoice"
android:listSelector="#drawable/list_selector" />
(Playing with choice mode does not help either).
The list_selector is an almost empty stub:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="#android:color/transparent" />
</selector>
I don't need specific styles for listview as a whole, so I'd leave a default one, but according to this answer, we need a selector for a listview for item selector to work. Anyway, without the list_selector the problem remains.
The listview item layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:background="#drawable/listitem_background"
android:orientation="vertical">
and it references the following listitem_background selector:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:drawable="#android:color/white" />
<item android:drawable="#android:color/transparent" />
</selector>
The problem is, that selected items do not have white background.
If I change android:state_selected="true" selector in the listitem_background to, for example, android:state_pressed="true", then the selector starts to work, that is item background becomes white if an item is touched.
So, I suppose, there is an error either in the selectors, or in the way how I select items.
I can write a workaround by setting background from Java or utilizing checkable states, but I want to understand and fix current problem with selectors. Thanks in advance.

What about adding this line in your item view?
android:background="?android:attr/activatedBackgroundIndicator"
For instance:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/activatedBackgroundIndicator"
android:orientation="vertical" >
<TextView
android:id="#+id/textViewListRowOption"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical" />
</LinearLayout>
Then the selector looks something like this:
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="#android:integer/config_mediumAnimTime">
<item android:drawable="#drawable/list_pressed" android:state_pressed="true"/>
<item android:drawable="#drawable/list_selected" android:state_activated="true"/>
<item android:drawable="#drawable/list_default"/>
</selector>
And the list view:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="#+id/listViewMainFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:listSelector="#drawable/list_item_selector"
android:choiceMode="singleChoice">
</ListView>
</LinearLayout>

Try this one to change the selected list item.Put it inside the list view.
if (currentSelectedView != null && currentSelectedView != v) {
unhighlightCurrentRow(currentSelectedView);
}
currentSelectedView = v;
highlightCurrentRow(currentSelectedView);
private void unhighlightCurrentRow(View rowView) {
rowView.setBackgroundColor(Color.TRANSPARENT);//to set a color for un-seclected row
}
private void highlightCurrentRow(View rowView) {
rowView.setBackgroundResource(R.drawable.selector_img);//to set a color for seclected row
}

Related

ListView item not changing background

I'm trying to change the background of a listview item when it's pressed, and despite having tried what has been mentioned in other SO posts the item refuses to change background when clicked.
What I'm I doing wrong?
EDIT: What I want to achieve:
This is how the default listview reacts when clicking an item (talking about the background change), but since I'm using custom list elements layout the list doesn't respond to clicks at all and is very dull, so I'm trying to achieve similar behaviour with the background changing whenever I click a list element.
I have this simple selector:
selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_pressed="true"
android:drawable="#drawable/selected_state" />
</selector>
selected_state.xml
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#color/darkblue" />
</shape>
I tried setting it to the selector of the listview and making the list view single choice
Main layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="100dp">
...
<LinearLayout
android:id="#+id/tab1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ListView
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:id="#+id/listViewCentral"
android:choiceMode="singleChoice"
android:listSelector="#drawable/selector" />
</LinearLayout>
...
</RelativeLayout>
List view item:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#drawable/selector">
...
</RelativeLayout>
And I used OnItemClick listener to set the state to selected
Main activity:
ListView list = (ListView)findViewById(R.id.listViewCentral);
list.setAdapter(stringAdapter);
list.setOnItemClickListener(new TsClickListener());
Listener:
public class TsClickListener implements AdapterView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
view.setSelected(true);
}
}
Logcat is empty (no errors)
try adding the property android:state_focused
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="#drawable/selected_state" />
<item android:state_focused="true" android:drawable="#drawable/selected_state" />
</selector>
The problem after all was the OnItemClick event wasn't being fired at all, and the solution was to add the 'clickable' attribute to the RelativeLayout of my list view element's layout and set it to true, everything works fine then.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="100dp"
android:clickable="true" <-- Problem
android:background="#drawable/selector">
...
</RelativeLayout>

Selector for Multi Choice ListView

I can't highlight a multichoice list view with custom adapter in android. The activated and pressed state works just fine. What I want is when the user taps on an item it should be highlighted.
my new_list_selector.xml
<?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="#drawable/list_selector_pressed" />
<item android:state_activated="true" android:drawable="#drawable/list_selector_selected" />
<item android:state_selected="true" android:drawable="#drawable/list_selector_pressed" />
</selector>
in the above xml, the states for "activated" and "pressed" are working but not "selected".
In my listview_item.xml I set the background to selector as follows
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="#drawable/new_list_selector">
<!--list items goes here-->
</RelativeLayout>
I define my list view like this
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/masterContainer">
<ListView
android:minWidth="25px"
android:minHeight="25px"
android:focusable="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/friendViewList" />
</RelativeLayout>
I get the activated state when I tap and hold a list item. The pressed state works when I tap the list item. I want it to be highlighted when the user taps the item. Can someone help me out on this? Thanks for any input in advance.
PS: I prefer xml solution over coding. I have also tried selector with state_focused set to true with no luck
Do the following:
listview_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="48dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/new_list_selector"/>
</RelativeLayout>
This will set the selector on ImageView. You can also do it with your two TexTviews.

Custom icons in expandablelistview have distorted dimensions

I have an expandablelistview that needs to have custom arrows. I tried setting the groupIndicator to a selector like so:
<ExpandableListView
android:id="#+id/home_drawer_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:childDivider="#android:color/transparent"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"
android:groupIndicator="#drawable/expandable_list_view_selector" />
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/arrow_down" android:state_expanded="true" />
<item android:drawable="#drawable/arrow_right" />
</selector>
However, for some reason this is distorting the dimensions of the arrows, see below:
Any idea why they're being distorted, and how to fix it?
It turns out that the issue was that I was setting padding on the TextView in the group header, which was then distorting the image. I found the whole default group header and custom indicator to be extremely cumbersome to work with, you can't really customize the row at all without distorting the image, so I ended up using a custom view for the group header instead.
Set the ExpandableListView's groupIndicator to #null:
<ExpandableListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:groupIndicator="#null" />
Add a custom group header, in my case ListViewGroupHeader.axml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="#dimen/padding">
<ImageView
android:id="#+id/group_header_arrow"
android:src="#drawable/arrow_right"
android:layout_centerVertical="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dp" />
<TextView
android:id="#+id/group_header_title"
android:layout_toRightOf="#+id/group_header_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="#color/black"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_centerVertical="true" />
</RelativeLayout>
Set the custom layout in your adapter's GetGroupView method, keying off of the isExpanded property for which image to show:
var layoutInflater = (LayoutInflater)ApplicationContext.Activity.GetSystemService (Context.LayoutInflaterService);
var view = layoutInflater.Inflate(Resource.Layout.ListViewGroupHeader, null);
var arrowImageView = view.FindViewById<ImageView> (Resource.Id.group_header_arrow);
var titleTextView = view.FindViewById<TextView> (Resource.Id.group_header_title);
arrowImageView.SetImageResource (isExpanded ? Resource.Drawable.arrow_down : Resource.Drawable.arrow_right);
titleTextView.Text = title;
if (isExpanded && colorExpandedBlue) {
arrowImageView.SetImageResource (Resource.Drawable.arrow_down_blue);
titleTextView.SetTextColor (ApplicationContext.Activity.Resources.GetColor (Resource.Color.standard_blue));
}
return view;
I did a simpler solution, not very elegant, but works. Used a layer list, positioning the drawable resource with padding on top and bottom, this results in a drawable with the expected proportion of my expandable list view. The amount of padding may be different to your view...
The icon I used was downloaded at https://material.io/icons/
Create two layer list drawable:
File ic_expand_more_expandable_list.xml in drawable:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="#drawable/ic_expand_less_white_24dp"
android:top="8dp"
android:bottom="8dp"
/>
</layer-list>
File ic_expand_more_expandable_list.xml in drawable:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="#drawable/ic_expand_more_white_24dp"
android:top="8dp"
android:bottom="8dp"
/>
</layer-list>
and use then as your state:
File group_arrow.xml in drawable:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/ic_expand_less_expandable_list"
android:state_expanded="true" />
<item android:drawable="#drawable/ic_expand_more_expandable_list" />
</selector>
And then add it as the group indicator of the ExpandableListView
android:groupIndicator="#drawable/group_arrow"
It is working perfectly here in all tested resolutions.

ListView Selector not working with ListViewItem's background set

I have a ListView that has a selector set with just a solid color.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:id="#+id/assignmentSelectedItem" />
<ListView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/assignmentsListView"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:listSelector="#drawable/assignment_list_selector" />
</LinearLayout>
assignment_list_selector.xml -
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="#android:color/white" />
<item android:drawable="#android:color/transparent"/>
</selector>
In the ListView.Adapter for my list, I have items that have their view's background set to a specific color. My question would be is that why the selector is not working at all in displaying a selected color for my list view? If so, any suggestion of a work around with allowing me to still set the view's background color.
You can use ListView property android:drawSelectorOnTop="true" in your layout .xml file in order to made list view to draw the selector over the list item rather than under them.
If you wonna have item's background + list selector functionality you can try another approach: Use transparent list selector. And modify your selector in order to use as a background for the list item. For example
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="#android:color/white" />
<item android:drawable="#android:color/your_list_item_color"/>
</selector>

Change Selection in a ListView from Orange to Green

How do I do this per selected list item.
I tried adding this to android:background
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true"
android:state_pressed="false"
android:drawable="#color/android_green" />
<item android:state_focused="true"
android:state_pressed="true"
android:drawable="#color/black_alpha" />
<item android:state_focused="false"
android:state_pressed="true"
android:drawable="#color/black_alpha" />
<item android:drawable="#color/white_alpha" />
</selector>
but it does not work, it changes the entire ListView.
Still not working, here is what I have so far
::listview_background
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:drawable="#color/black_alpha" />
<item android:drawable="#color/white_alpha" />
</selector>
::My view that is using the above
<ListView android:id="#+id/list" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_below="#+id/round"
android:listSelector="#drawable/listview_background">
</ListView>
The problem is that the black_alpha will apply the the entire list, not just the selected list item
Here's a good article on how to use selectors with lists.
Instead of setting it to be the android:background of the ListView, I believe you want to set android:listSelector as shown below:
<ListView android:id="#+id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:divider="#null"
android:dividerHeight="0dip"
android:listSelector="#drawable/list_selector" />
Jax, you said that:
The problem is that the black_alpha will apply the the entire list, not just the selected list item
I had the same problem. After playing around with it for a while, I was able to get it to stop applying the color to the whole list by using a 3x3 png image of the color I wanted instead of applying a color. So for some weird reason if you use a color you get the odd background behavior, when you use a png, it works fine. :S
So that is one way to get around it.
-----Another way----------
I found the best results when I set the listView selector to not have any states like this:
res/drawable/list_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
</selector>
Then I take care of all the states in the background of the list item. NOT in the selector. I found I had more control this way.
res/color/list_item_bg.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="false"
android:state_pressed="false"
android:drawable="#color/list_item_black_translucent" />
<item android:state_pressed="true"
android:drawable="#color/light_green_accent_translucent" />
</selector>
Then here is my list item:
res/layout/simple_list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingRight="45dip"
android:paddingBottom="2dip"
android:layout_gravity="center_vertical"
android:background="#color/list_item_bg">
<ImageView
android:id="#+id/arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="8dip"
android:src="#drawable/list_item_arrow" />
<TextView
android:id="#+id/simple_list_item_label"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:textSize="12sp"
android:textColor="#color/list_label_color"/>
</LinearLayout>
I was also facing your problem where the color change applies to the whole list.
But now its working for me now:
My main page containing the listview (noticed I did not apply the listselector here):
<ListView
android:id="#+id/controlList" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
Instead applied the listselector to getView, its like tell that particular row (convertView) to use the listselector.xml in drawable foldable when its state changes, e.g. pressed, focused...:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if(convertView == null){
LayoutInflater li = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
convertView = li.inflate(R.layout.control_list, null);
viewHolder = new ViewHolder();
viewHolder.topText = (TextView) convertView.findViewById(R.id.toptext);
viewHolder.bottomText = (TextView) convertView.findViewById(R.id.bottomtext);
convertView.setTag(viewHolder);
}
else{
viewHolder = (ViewHolder) convertView.getTag();
}
//each convertView will be assigned the listselector
convertView.setBackgroundResource(R.drawable.listselector);
viewHolder.topText.setText(testSchemes[position]);
//viewHolder.vText.setText(testDetails[position]);
return convertView;
}
And finally my listselector.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false"
android:state_selected="false"
android:drawable="#color/lightgreen" />
<!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
<item android:state_pressed="true"
android:drawable="#color/darkgreen" />
<item android:state_selected="true" android:state_pressed="false"
android:drawable="#color/orange" />
</selector>
This is what the above code does:
All entries when first loaded are lightgreen.
Scrolling up and down using cursor highlights the selected entry orange.
Pressing a row turns it to darkgreen.
As bigstones mentioned in a comment, a working solution is using a shape instead of a color (I was also getting the whole list highlighted). Here is a complete solution:
add these 2 attributes to the listview:
android:drawSelectorOnTop="true"
android:listSelector="#drawable/my_list_selector"
add my_list_selector.xml to drawable folder:
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android:color="#77526F35"/>
</shape>
Now the list items should show a semitransparent green overlay on pressed state.
I faced the same issue and then I just needed a simple line in my item view xml.
android:background="?android:attr/activatedBackgroundIndicator"
Check this post: This post could help

Categories

Resources