Have read over a number of related questions here at SO, as well as looked through the Android docs and source to try to figure this out, but I am stumped, although given that the listSelector seems to only apply styles on selected items, I'm not shocked...
I have a Listview defined in main.xml here:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ListView
android:id="#android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fadingEdgeLength="5dp"
android:divider="#000000"
android:dividerHeight="1dp"
android:listSelector="#drawable/list_selector" />
<TextView
android:id="#android:id/empty"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:singleLine="false"
android:text="#string/message_list_empty" />
</FrameLayout>
The listSelector referenced is here (borrowed largely from the default Android State List found in the SDK: /android/platforms/android-8/data/res/drawable/list_selector_background.xml):
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- the window has lost focus, disable the items -->
<item
android:state_window_focused="false"
android:drawable="#drawable/shape_row_disabled" />
<!-- the list items are disabled -->
<item
android:state_enabled="false"
android:state_focused="true"
android:state_pressed="true"
android:drawable="#drawable/shape_row_disabled" />
<item
android:state_enabled="false"
android:state_focused="true"
android:drawable="#drawable/shape_row_disabled" />
<item
android:state_enabled="false"
android:drawable="#drawable/shape_row_disabled" />
<!-- the list items are enabled and being pressed -->
<item
android:state_focused="true"
android:state_pressed="true"
android:drawable="#drawable/shape_row_transition" />
<item
android:state_focused="false"
android:state_pressed="true"
android:drawable="#drawable/shape_row_transition" />
<!-- the list items are enabled and being used -->
<item
android:state_focused="true"
android:drawable="#drawable/shape_row_selected" />
<!-- the default item -->
<item
android:drawable="#drawable/shape_row" />
</selector>
The drawables referenced are shapes, rounded rectangles, like so:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="#EF6100"
android:centerColor="#FF8E00"
android:endColor="#EF6100"
android:angle="270" />
<corners
android:bottomRightRadius="7dp"
android:bottomLeftRadius="7dp"
android:topLeftRadius="7dp"
android:topRightRadius="7dp" />
</shape>
So, the end result should be a ListView with items with a #drawable/shape_row background by default, and then different colored backgrounds depending on the state. When I fire up my list, everything works fine in terms of when states are active, such as an item gets focus, is pressed, etc, but the items themselves have a transparent background when none are selected (i.e. the default view state). I had hoped that the last rule of the State List,
<item android:drawable="#drawable/shape_row" />
would capture that state, but for some reason it is not working. I have moved things around and tried different settings, and nothing. If I edit the row.xml file which I use to define the list items in the ListView and try to add a specific android:background that points to #drawable/shape_row, every row gets the correct background, BUT on pressed, on focus, etc states fail to process (or at least, can't be seen as the background never changes).
Can anyone point me in the right direction here? I am SO close to putting this one to bed, but after trying nearly everything, just can't get the ListView items to take a default background AND respond to the implemented State List via android:listSelector.
Thanks,
Paul
EDIT:
Also just tried adding android:itemBackground="#drawable/shape_row" to the ListView in main.xml, and unsurprisingly no luck (the docs state it should be used to specify menu items' backgrounds, but thought it was worth a shot with list items).
Another thing tried, adding android:visible="true" to each of the selector and item definitions. The StateListDrawable docs seem to indicate that the "Provides initial visibility state of the drawable; the default value is false", but adding this changed nothing.
EDIT2: So, based on the research done below by Qberticus, it seems that there can be only one set of list selectors per view, which confirms the list selector behavior. I can also confirm that setting the android:drawSelectorOnTop does move the selector IN FRONT of the selected item, but this of course obscures the item itself such that I only see the selector itself (which in my case is a colored shape).
Here is what the list looks like with backgrounds set:
Due to the set background, there is no change in appearance when items are selected. If I change the android:drawSelectorOnTop directive to true and select an item, I get:
And finally, if I set no background image for the list items, the selector works as expected, but of course, there are no background images as the last rule of the StateSelector does not appear to be followed (shouldn't it act as a catchall?) for non-selected items meaning no nice custom rounded shapes:
So, my problem remains; if I don't set a background for each list item, I can see the selector working BUT the items have no background when not selected. If I set a background for the item, they look great when not selected, but the background obscures the selector. Is it simply not possible to have a uniquely shaped list item with working selectors?
Thanks for anyone else who can weight in.
Figured this out, the issue was that while I was setting the listSelector for the ListView to the State List correctly via android:listSelector="#drawable/list_selector", I also needed to set the background for the list item to another State List via android:background="#drawable/list_background"
In the list_background.xml state list, I have:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:visible="true">
<!-- the list items are disabled -->
<item
android:state_window_focused="false"
android:drawable="#drawable/shape_row_disabled" />
<!-- the list items are enabled, in focus but not being touched/pressed (idle) -->
<item
android:state_window_focused="true"
android:state_pressed="false"
android:state_focused="false"
android:state_selected="false"
android:drawable="#drawable/shape_row" />
<!-- the catch-all -->
<item
android:drawable="#android:color/transparent" />
</selector>
Found the answer here:
Changing background color of ListView items on Android
In conjunction with my list selector above, it works perfectly.
The listSelector is only used to specify a View that will be drawn in the same place as the selected item View. I.e., there is only one instance of the listSelector per ListView. You can specify if it can draw on top or not using drawSelectorOnTop.
If you want all your Views to use a state list then you should specify that where the child Views are defined.
I'm using the source for AbsListView as reference. Specifically AbsListView#setSelector(Drawable), AbsListView#positionSelector, AbsListView#drawSelector, and AbsListView#dispatchDraw
AbsListView#drawSelector:
private void drawSelector(Canvas canvas) {
if (shouldShowSelector() && mSelectorRect != null && !mSelectorRect.isEmpty()) {
final Drawable selector = mSelector;
selector.setBounds(mSelectorRect);
selector.draw(canvas);
}
}
AbsListView#positionSelector:
void positionSelector(View sel) {
final Rect selectorRect = mSelectorRect;
selectorRect.set(sel.getLeft(), sel.getTop(), sel.getRight(), sel.getBottom());
positionSelector(selectorRect.left, selectorRect.top, selectorRect.right,
selectorRect.bottom);
final boolean isChildViewEnabled = mIsChildViewEnabled;
if (sel.isEnabled() != isChildViewEnabled) {
mIsChildViewEnabled = !isChildViewEnabled;
refreshDrawableState();
}
}
The source indicates that there is only one mSelector created/used and that it is positioned in the same bounding rect as the selected item.
You can assign default background for root layout and selector_background for child, in this case if item not selected then default background not obscures the selector. Its work for me.
Related
I'm porting my app to Chrome OS and there are a few places in the app where arrow key navigation works, but the current focused element is not highlighted in any way. I've found that whenever I set a background color for an element like
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
...
android:background="#color/white" >
...
</LinearLayout>
then the default highlighting of the focused element will not show. Removing this will show the default background (which is not always the same as what I want).
Also, in cases where I use a selector in a ListView, the background is in front of the intended highlighting drawable (which can be seen if the color is somewhat transparent).
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="#android:integer/config_mediumAnimTime" >
<item android:state_pressed="false" android:state_focused="true" android:drawable="#drawable/list_focused" />
<item android:state_pressed="true" android:drawable="#drawable/list_pressed" />
<item android:drawable="#color/white" />
</selector>
This is even more strange since I was under the (possibly incorrect) impression that selectors will only pick one of the items.
I can't post too much code since this is work code, but this is happening throughout the app wherever there's a list.
If you have a selector defined for the views in your ListView, set the drawSelectorOnTop property to true on your ListView, as per the docs.
I've been working on a project, and part of it includes a list view. When an item in the list view is clicked, it links to another activity. But when I tap it, there is no immediate reaction. For example, in one of my activities I have a button, and I'm using setOnTouchListener so that when the button is pressed, it has a color filter and one it is released, the filter goes away and the next activity opens. I want to have a similar effect with the list view item.
I've tried using onTouchListener on the listView to do the same task but it doesn't work. I'm using setSelected(bool) in order to change the background of the list view using the android:state_selected property in the xml file. (see here for how I was doing it Android ListView selected item stay highlighted).
But it doesn't work, as the view in the onTouchListener isn't the same as the view that I need (the specific list view item). So is there a way to highlight an item in a list view while it is pressed?
you have to make selector for this. like,
list_item_selector.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"
color android:color="#FF0000"/>
<item android:state_pressed="true">
<color android:color="#AA736F6E" />
</item>
<item android:state_selected="true"
android:state_pressed="false">
<color android:color="#00000000"/>
an you have to set this selector in listview as well as layout for listitem. like this,
<ListView
android:id="#+id/mylist"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:cacheColorHint="#AA736F6E"
android:clickable="true"
android:background="#drawable/list_item_selector"
android:divider="#737CA1"
android:dividerHeight="0.5dp"
android:choiceMode="singleChoice">
</ListView>
and set in list item
hops it is work
So my graphics artist came to me with a really cool layout for controls on our new app. The problem is getting these images laid out since most views in android are rectangular. See image for what I have to work with.
Any idea how to layout these buttons so they shape around each other if that makes sense?
If the problem is the layout, you can draw the buttons and save it as png. You can layout your app by RelevantLayout . And use the "selector" to change the button image when user press an so on.
selector example: "drawable/selector1.xml"
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:state_pressed="true" android:drawable="#drawable/buttonClicked" /> <!-- focused and pressed-->
<item android:state_pressed="true" android:drawable="#drawable/buttonClicked" /> <!-- pressed -->
<item android:drawable="#drawable/button" /> <!-- default -->
</selector>
use it like this:
android:background="#drawable/selector1"
the Views in android are rectangular, that is correct. The only workaround I see here: use multiple "invisible" Buttons (alpha set to 0). You can position them around the screen and assign the same action to some of them. Of course you'll need to implement the OnClickListener and use switch-case.
Hi I am working on an application in which when I select on an listitem its background color should change and it should also show a vertical bar of single color at left side of listitem like it appears in youtube application.
The image is attached below:
I know how to change background color on listview item click but how do I add the red line which is apprearing in youtube application. For this I have thought of adding a view in listview item xml which I would make visible on item click event.But in that case how would I hide the view from other listview items? Or is their any other easy way to implement this?
Try to use this drawable for item state_pressed:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<solid android:color="#android:color/holo_red_dark" />
</shape>
</item>
<item android:left="10dp">
<shape>
<solid android:color="#android:color/black" />
</shape>
</item>
</layer-list>
You should implement a background selector. To do that create a XML file with different drawables for different row states (selected, focused etc.). You can find many examples on how to do that. For example:
<?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/pressed"/> <!-- pressed -->
<item android:state_focused="true" android:drawable="#drawable/focused" /> <!-- focused -->
<item android:drawable="#drawable/default"/> <!-- default -->
</selector>
After that just set your row background Drawable to this file.
To create a list view of that sort you will need to create custom adapters. Creating a view with all the elements present in it. Populating list using the custom ArrayListAdapter and using background selector for the background color.
Also, for the vertical bar default view will be invisible and made visible to the selection. Create a public static list to keep the track of selection even after the view is closed.
WARNING: The XML in this question is wrong, read the answer before you confuse yourself!
I have been banging my head on the wall for a while now. The following posts have shed light on the subject, but failed to solve my issue: Android ListView State List not showing default item background and ListView item background via custom selector
The proper nine-patch background shows perfectly when I select the list item, but I can not get the default nine-patch background to show initially. It seems to me that I need to set the default item background somehow, but I can't figure out how to do so.
List View:
<?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="fill_parent"
android:orientation="vertical">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/shopListHeader"
/>
<ListView
android:id="#+id/shopList"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:dividerHeight="0px"
android:divider="#FFFFFFFF"
android:listSelector="#drawable/shop_list_selector"
/>
</LinearLayout>
Selector:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:visible="true">
<!-- the list items are enabled and being pressed -->
<item
android:state_pressed="true"
android:drawable="#drawable/shop_list_item_pressed" />
<item
android:state_selected="true"
android:textColor="#FFFFFFFF" />
</selector>
Background:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:visible="true">
<item
android:state_selected="true"
android:drawable="#android:color/transparent" />
<item
android:drawable="#drawable/shop_list_item" />
</selector>
As you can see, I have dumbed down the examples from the references.
You may also notice that the Background selector isn't being referenced anywhere. I started tossing it in random places (if the app compiled the addition either had no effect or cause a forced close)
I have also made an attempt to stop the color of the text from changing to black and grey when an item is selected but not pressed (can be done by scrolling through the list). Since my background will be black in the center, the text becomes partially invisible when selected. That addition (the last item node in the Selector) does nothing, as far as I can tell.
Does anyone have any thoughts on getting this ridiculously time consuming functionality working?
I was gonna delete this thread, but I can't so I'll see if I can't use this as an example of what not to do :)
First, in the ListView XML: android:listSelector="#drawable/shop_list_selector"
Don't do that!
What I was trying to do here was set the background of the list items and the android:background property didn't work. You may have noticed that the item XML is missing, and that is because it was missing from my head! (I never touched it over the countless hours I was hammering away at this 'issue') So the line android:background="#drawable/shop_list_selector" goes in the item's properties and everything is groovy. (Remember the XML above is very wrong so don't use it!)
...Well except that it doesn't look as good in real life as it did in my head :(
Back to the drawing board!!!
You havent defined a "normal" state, see this example
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#color/blue"
android:state_pressed="true" />
<item android:color="#color/red"
android:state_selected="true" />
<item android:color="#color/white" />
</selector>
in here white is the "normal" state, in here you can find some documentation about it.
I hope this helps