I'm trying to use a list view control on Lollipop under the following conditions:
The theme type is the default Theme.Material (dark theme).
The list view is contained inside of larger layout which has a white background.
The list view should have a list selector that appears with the white background.
NOTE: I am forced to use a custom list selector color because if I use a white background, the dark material themed selector uses the theme's colorControlHighlight color for the ripple, which is 40ffffff, and does not show up.
I first tried the following:
layout xml
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#android:color/white" >
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ListView
android:id="#+id/list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:listSelector="#drawable/list_selector" />
</LinearLayout>
list_selector xml
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#ff0000" >
</ripple>
And list view row xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:gravity="center_vertical"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables" >
<ImageView
android:id="#+id/list_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/list_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
What I am expecting to see is when I select an item, the item is selected with a ripple colored as #ff0000. However, this is what I end up seeing:
What I am hoping for is somewhat close to this behavior - but confined within the selected list row! What am I doing wrong?
Thanks,
Zach
You're using an unbounded ripple, e.g. a ripple with no content or mask layer, so the ripple is projecting onto the background of its parent ListView. You should set a mask layer to constrain the ripple bounds.
res/drawable/my_list_selector.xml:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlHighlight">
<item android:id="#android:id/mask">
<color android:color="#color/white" />
</item>
</ripple>
Related
I have implemented the ripple effect introduced in Lollipop in a ListView. But it is only working for the first item of ListView. I've followed the answers of this question but I'm unable to set a ripple effect.
I have a ripple_background.xml in drawable-v21 folder:
<ripple
xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#android:color/background_dark">
<item>
<shape
android:shape="oval">
<solid android:color="?android:colorAccent" />
</shape>
</item>
</ripple>
The layout my ListView exists in is as following:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ListView
android:id="#+id/listSettings"
android:listSelector="#android:color/transparent"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:divider="#color/price_item_divider"
android:dividerHeight="1dp"
android:drawSelectorOnTop="true"/>
</LinearLayout>
and the items populated inside ListView is as follows (settings_item_row.xml):
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="70dp"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:background="#drawable/ripple_background"
android:padding="16dp" >
<ImageView
android:id="#+id/imageViewIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:paddingRight="10dp" />
<TextView
android:id="#+id/textViewName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="#+id/imageViewIcon"
android:paddingRight="10dp"
android:textColor="#android:color/black"
android:textSize="18sp" />
</RelativeLayout>
Thank you for your help!
I faced same issue and found an easy solution to this problem. No need to set any background to any list item or ListView. Just set android:listSelector to your ripple drawable in ListView.
So ListView in my activity look like:
<ListView
android:id="#+id/myListView"
...
android:listSelector="#drawable/ripple" />
and my ripple drawable is defined as :
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/rippleColour">
<item android:drawable="#color/backgroundColour"/>
</ripple>
Just had this problem and fixed it. Remove the ripple background drawable from your individual list item views, and then set a background on the ListView itself. As well, add the drawSelector to your list item and remove field from your ListView.
This fix only works for having a single color background for the ListView.
Your List Item View:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="70dp"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:background="#drawable/ripple_background"
android:padding="16dp" >
And Your ListView:
<ListView
android:id="#+id/listSettings"
android:listSelector="#android:color/transparent"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:divider="#color/price_item_divider"
android:dividerHeight="1dp"
android:background="#color/__Your color here__
/>
It happened to me and I changed the clickable value to true than it worked.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
....
android:background="#drawable/touchselector"
android:clickable="true">
....
</LinearLayout>
There is no need to add any background to the layout.
Just leave your layouts as it is. Now concentrate on the ListView
in ListView your can add your own background and you can use ListSelector to apply ripple theme.
By using ListSelector in ListView ripple effect will work on every item in the list and you can give default background to the list items also (separately in list View).
<ListView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/list"
android:scrollbarStyle="outsideInset"
android:background="#fff"
android:listSelector="#drawable/ripp" />
Standard ListView selector in android L developer preview uses colorControlHighlight for the ripple effect on touch and has a transparent background in unfocused state.
I would like to define a ListView item that has a colored background and still shows the ripple effect on touch with the same highlight color. Now, if I define the following drawable:
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:colorControlHighlight">
<item android:drawable="#color/my_background_color"/>
</ripple>
it works, but the ripple starts in the middle of the ListView item, regardless of the touch position. If I use the same background outside of the ListView, e.g. for a LinearLayout, it works like expected (the ripple starts on the touch position).
I've managed to get individually colored list items while maintaining the ripple effect. Set the background of your list items using whatever adapter you have and set the listview to show the selector on top:
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawSelectorOnTop="true" />
This will draw the ripple effect above the background.
As far as I can tell this bug is only in Android 5.0, not 5.1. The trick seems to be to use Drawable#setHotspot as a Google dev hints to here https://twitter.com/crafty/status/561768446149410816 (because obscure twitter hints are a great form of documentation!)
Assume you have a row layout something like this
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/row_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="?attr/selectableItemBackground">
.... content here .....
</LinearLayout>
</FrameLayout>
The following worked for me
row.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
v.findViewById(R.id.row_content)
.getBackground()
.setHotspot(event.getX(), event.getY());
return(false);
}
});
I've found that it only seems to work correctly if you apply the background to the root element of the list item.
Also, consider using the new RecyclerView instead of a ListView
List item view example:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/list_padding"
android:layout_marginLeft="#dimen/list_padding"
android:layout_marginRight="#dimen/list_padding"
android:padding="#dimen/list_padding"
android:background="#drawable/ripple_bg">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Large Text"
android:id="#+id/tvTitle"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Small Text"
android:id="#+id/tvSubtitle" />
</RelativeLayout>
i adapted #ArhatBaid 's answer a littlebit, tested it and it works perfectly:
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:colorControlHighlight">
<item android:drawable="#color/light_grey_header_navigation_drawer"/>
</ripple>
So, this allows you to set a background color and still have the ripple effect.
for me target and minSdk are 21.
The sample layout, which contains the Ripple effect as Background of the the parent layout.
<RelativeLayout
android:id="#+id/id4"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/ripple_effect"
android:clickable="true">
<ImageView
android:id="#+id/id3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:background="#drawable/image"
android:layout_centerVertical="true"/>
<LinearLayout
android:id="#+id/id2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_alignParentRight="true"
android:layout_centerVertical="true">
<TextView
android:id="#+id/id1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/text"/>
</LinearLayout>
</RelativeLayout>
Ripple_effect.xml
Here you can use any colour of you choice.
Make sure that you use sdk version 21 and have drawable-v21 and style-v21 folder and put all the file related to v21 in them.
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:colorControlHighlight">
<item android:id="#android:id/mask">
<shape android:shape="oval">
<solid android:color="?android:colorAccent" />
</shape>
</item>
Here you can use different shape like rectangle instead of oval...
You can achieve this with a nested Layout. Just create e.g. a LinearLayout as root layout around your existing layout, set the ripple effect on the root layout and your background color to the nested one.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/ripple_effect"
android:orientation="vertical">
<RelativeLayout xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/containterContent"
android:background="#color/yourCOLOR"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Your content -->
</RelativeLayout>
</LinearLayout>
I have set this color:
<color name="lightgrey">#1a000000</color>
And have this layout with a textview that as margins and one listview.
As you can see in the below image, there's a slightly difference in the background color of the texviewand the listview
Why is this happening?
Here is my layout:
<?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:background="#color/lightgrey"
android:orientation="vertical"
>
<TextView
android:id="#+id/queryTitle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10sp"
android:background="#drawable/rect"
android:clickable="false"
android:gravity="center"
android:minHeight="50dp"
android:textColor="#000000"
android:textSize="30sp"
android:textStyle="bold"
android:typeface="normal"
/>
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="false"
android:divider="#null"
android:fastScrollEnabled="true"
android:textFilterEnabled="true"/>
</LinearLayout>
And #drawable/rect
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#color/white"/>
<corners
android:bottomLeftRadius="5dip"
android:bottomRightRadius="5dip"
android:topLeftRadius="5dip"
android:topRightRadius="5dip"/>
Change the background colour into proper format like #e3e3e3 (max 6 chars) as android probably ignores the rest of the chars. Change the background color to a max 6 char color set and see if it works.
Check the layout you use for the list items, maybe you are using a different background color to the background of the main layout.
... and remember add always the next attribute on the ListView Tag to avoid having a black background when scroll the list.
android:cacheColorHint="#00000000" // setting transparent color
I'm trying to add a divider to a horizontal linear layout but am getting nowhere. The divider just doesn't show. I am a total newbie with Android.
This is my layout XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/llTopBar"
android:orientation="horizontal"
android:divider="#00ff00"
android:dividerPadding="22dip"
android:showDividers="middle">
<Button
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="asdf" />
<Button
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="asdf" />
</LinearLayout>
</RelativeLayout>
use this for horizontal divider
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="#color/honeycombish_blue" />
and this for vertical divider
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#color/honeycombish_blue" />
OR if you can use the LinearLayout divider, for horizontal divider
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<size android:height="1dp"/>
<solid android:color="#f6f6f6"/>
</shape>
and in LinearLayout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="#drawable/divider"
android:orientation="vertical"
android:showDividers="middle" >
If you want to user vertical divider then in place of android:height="1dp" in shape use android:width="1dp"
Tip: Don't forget the android:showDividers item.
Try this, create a divider in the res/drawable folder:
vertical_divider_1.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<size android:width="1dip" />
<solid android:color="#666666" />
</shape>
And use the divider attribute in LinearLayout like this:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:divider="#drawable/vertical_divider_1"
android:dividerPadding="12dip"
android:showDividers="middle"
android:background="#ffffff" >
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
<Button
android:id="#+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
</LinearLayout>
Note: android:divider is only available in Android 3.0 (API level 11) or higher.
It is easy to add divider to layout, we don't need a separate view.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:divider="?android:listDivider"
android:dividerPadding="2.5dp"
android:orientation="horizontal"
android:showDividers="middle"
android:weightSum="2" ></LinearLayout>
Above code make vertical divider for LinearLayout
Update: pre-Honeycomb using AppCompat
If you are using the AppCompat library v7 you may want to use the LinearLayoutCompat view. Using this approach you can use drawable dividers on Android 2.1, 2.2 and 2.3.
Example code:
<android.support.v7.widget.LinearLayoutCompat
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:showDividers="middle"
app:divider="#drawable/divider">
drawable/divider.xml: (divider with some padding on the top and bottom)
<?xml version="1.0" encoding="UTF-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetBottom="2dp"
android:insetTop="2dp">
<shape>
<size android:width="1dp" />
<solid android:color="#FFCCCCCC" />
</shape>
</inset>
Very important note: The LinearLayoutCompat view does not extend LinearLayout and therefor you should not use the android:showDividers or android:divider properties but the custom ones: app:showDividers and app:divider. In code you should also use the LinearLayoutCompat.LayoutParams not the LinearLayout.LayoutParams!
I just ran into the same problem today. As the previous answers indicate, the problem stems from the use of a color in the divider tag, rather than a drawable. However, instead of writing my own drawable xml, I prefer to use themed attributes as much as possible. You can use the android:attr/dividerHorizontal and android:attr/dividerVertical to get a predefined drawable instead:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:showDividers="middle"
android:divider="?android:attr/dividerVertical"
android:orientation="horizontal">
<!-- other views -->
</LinearLayout>
The attributes are available in API 11 and above.
Also, as mentioned by bocekm in his answer, the dividerPadding property does NOT add extra padding on either side of a vertical divider, as one might assume. Instead it defines top and bottom padding and thus may truncate the divider if it's too large.
You can use the built in divider, this will work for both orientations.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="?android:attr/listDivider"
android:orientation="horizontal"
android:showDividers="middle">
Frustratingly, you have to enable showing the dividers from code in your activity. For example:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set the view to your layout
setContentView(R.layout.yourlayout);
// Find the LinearLayout within and enable the divider
((LinearLayout)v.findViewById(R.id.llTopBar)).
setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE);
}
If the answer of Kapil Vats is not working try something like this:
drawable/divider_horizontal_green_22.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<size android:width="22dip"/>
<solid android:color="#00ff00"/>
</shape>
layout/your_layout.xml
LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/llTopBar"
android:orientation="horizontal"
android:divider="#drawable/divider_horizontal_green_22"
android:showDividers="middle"
>
I encountered an issue where the padding attribute wasn't working, thus I had to set the height of the divider directly in the divider.
Note:
If you want to use it in vertical LinearLayout, make a new one, like this:
drawable/divider_vertical_green_22.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<size android:height="22dip"/>
<solid android:color="#00ff00"/>
</shape>
Your divider may not be showing due to too large dividerPadding. You set 22dip, that means the divider is truncated by 22dip from top and by 22dip from bottom. If your layout height is less than or equal 44dip then no divider is visible.
In order to get drawn, divider of LinearLayout must have some height while ColorDrawable (which is essentially #00ff00 as well as any other hardcoded color) doesn't have. Simple (and correct) way to solve this, is to wrap your color into some Drawable with predefined height, such as shape drawable
You have to create the any view for separater like textview or imageview then set the background for that if you have image else use the color as the background.
Hope this helps you.
So. You know how when you click a post in the Google+ app, the entire View becomes blue. I want to do that as well, but with an ImageView.
I have the following code snippet, setting the actual image as the background and the selector as the main resource. This looks good, but doesn't respect scaleType for the background image:
<ImageView
android:id="#+id/painting_image"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#drawable/img"
android:src="#drawable/selector"
android:scaleType="centerCrop" />
By the way, #drawable/selector is just a selector that shows a tranparent color for state_pressed:
<item android:state_pressed="true">
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#44521400" />
</shape></item>
How can I make this work while respecting the scaleType?
Wrap your ImageView in a FrameLayout, and define the FrameLayout to be clickable. Be careful to assign the onClick event to the FrameLayout, and not to the ImageView, or the effect will break! Also note that foreground has been set to a selector, not background.
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:foreground="#drawable/imagebutton_selector" >
<ImageView
android:id="#+id/painting_image"
android:layout_width="match_parent"
android:layout_height="250dp"
android:scaleType="centerCrop" />
</FrameLayout>
ScaleType is only applied to the src drawable, not the background. Consider using the second option with an overlay view where you'll be implementing the click action, like this:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="#+id/painting_image"
android:layout_width="match_parent"
android:layout_height="250dp"
android:scaleType="centerCrop" />
<View
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="#drawable/imagebutton_selector"
android:onClick="onImageClick" />
</FrameLayout>