How to set state_selected in ripple drawable - android

How to specify android:state_selected inside a RippleDrawable
I have following xml for ripple drawable but background color doesn't show up when I set myView.setSelected(true);
<?xml version="1.0" encoding="utf-8"?>
<ripple
xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#DDDDDD"
>
<item android:id="#android:id/mask">
<shape>
<solid
android:color="#color/black" />
</shape>
</item>
<item android:state_selected="true">
<shape>
<solid
android:color="#EEEEEE" />
</shape>
</item>
<item>
<color android:color="#FFFFFF" />
</item>
</ripple>

Found the answer, just in case someone else having the same problem
<?xml version="1.0" encoding="utf-8"?>
<ripple
xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#DDDDDD"
>
<item>
<selector>
<item android:state_selected="true">
<color android:color="#EEEEEE" />
</item>
<item android:state_activated="true">
<color android:color="#EEEEEE" />
</item>
<item>
<color android:color="#FFFFFF" />
</item>
</selector>
</item>
</ripple>

To add to #Sohaib 's answer:
#Alanv is right that the OP didn't need a mask. But if one of your selector states is transparent and you need a mask it goes here:
<?xml version="1.0" encoding="utf-8"?>
<ripple
xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/ripple_color">
<!-- mask here... -->
<item android:id="#android:id/mask">
<color android:color="#color/black"/> <!-- any color will do -->
</item>
<item>
<selector>
<!-- ... NOT here. -->
<item android:state_selected="true">
<color android:color="#color/blue"/>
</item>
<item android:state_activated="true">
<color android:color="#color/red"/>
</item>
<item>
<color android:color="#color/transparent"/>
</item>
</selector>
</item>
</ripple>
I initially had the mask inside my selector and :boom:

Combining the above answer with other answers from:
What should be the color of the Ripple, colorPrimary or colorAccent? (Material Design)
Gives a nice ripple effect which also works for when the item is in a selected state.
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlHighlight">
<!-- Ripple mask - applied to all selector states -->
<item android:id="#android:id/mask">
<color android:color="#42ffffff" />
</item>
<!-- Selected state of item -->
<item>
<selector>
<item android:state_selected="true">
<color android:color="?attr/colorAccent" />
</item>
</selector>
</item>
</ripple>
This goes in your drawable-v21 folder, for other platforms you can just create a selector which uses the accent color:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/accent" android:state_selected="true"/>
<item android:drawable="#color/accent" android:state_pressed="true"/>
</selector>

I wanted to mimic the behavior of the Material Design checkboxes but I couldn't get them right until I used a ColorStateList like this:
In drawable-v21/bg_checkbox_ripple.xml
<?xml version="1.0" encoding="utf-8"?>
<ripple
xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/checked_accent_statelist"
android:radius="24dp">
</ripple>
In color/checked_accent_statelist.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?colorControlHighlight" android:state_checked="false"/>
<item android:color="?android:textColorHighlight" android:state_checked="true"/>
</selector>
The attribute "?android:textColorHighlight" is your accent color but with the right transparency for using it in ripples (I think it is 26%).
Also, you should provide a fallback for pre API 21 devices in drawable/bg_checkbox_ripple.xml
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="#android:integer/config_shortAnimTime">
<item>
<shape android:innerRadius="24dp" android:shape="oval">
<solid android:color="#color/checked_accent_statelist"/>
</shape>
</item>
</selector>

Related

Navigation Drawer item divider with selected background color

I have a navigation drawer in my android app. Here's the code:
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="right"
android:fitsSystemWindows="true"
android:background="#color/white"
app:headerLayout="#layout/nav_header"
app:menu="#menu/drawer_menu"
app:itemTextColor="#color/drawer_item"
app:itemIconTint="#color/drawer_item"
app:itemBackground="#drawable/nav_divider"/>
I've used one the answer to this post to add dividers between the items. Here's the nav_divider drawable that I'm using as itemBackground in my NavigationView:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:left="#dimen/activity_horizontal_margin">
<shape android:shape="rectangle">
<solid android:color="#color/light_gray"/>
</shape>
</item>
<item android:bottom="1dp">
<shape android:shape="rectangle">
<solid android:color="#color/white"/>
</shape>
</item>
</layer-list>
Now, the question is how do I change the background color of the selected item. I know how to do that without the divider, but with the divider, it's more complicated.
UPDATE:
Here's what I've tried:
I created another drawable called nav_divider_selected which is exactly like the nav_divider above except with different colors.
Then, I created a drawer_item_background drawable like this:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/nav_divider_selected" android:state_selected="true"/>
<item android:drawable="#drawable/nav_divider"/>
</selector>
And, replaced the itemBackground of the NavigationView with this new selector (app:itemBackground="#drawable/drawer_item_background"). But, it didn't work. The items all look black, for some reason.
I got it. It was a simple issue. I was just using the wrong state. So, here's the solution. I created two different layer lists (to add the divider to the navigation items):
nav_divider:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:left="#dimen/activity_horizontal_margin">
<shape android:shape="rectangle">
<solid android:color="#color/light_gray"/>
</shape>
</item>
<item android:bottom="1dp">
<shape android:shape="rectangle">
<solid android:color="#color/white"/>
</shape>
</item>
</layer-list>
nav_divider_selected:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:left="#dimen/activity_horizontal_margin">
<shape android:shape="rectangle">
<solid android:color="#color/light_gray"/>
</shape>
</item>
<item android:bottom="1dp">
<shape android:shape="rectangle">
<solid android:color="#color/light_blue"/>
</shape>
</item>
</layer-list>
Then, created a drawer_item_background drawable like this (state_checked should be used not state_selected):
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/nav_divider_selected" android:state_checked="true"/>
<item android:drawable="#drawable/nav_divider"/>
</selector>
And, then I used this drawable as itemBackground in my NavigationView:
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="right"
android:fitsSystemWindows="true"
android:background="#color/white"
app:headerLayout="#layout/nav_header"
app:menu="#menu/drawer_menu"
app:itemTextColor="#color/drawer_item"
app:itemIconTint="#color/drawer_item"
app:itemBackground="#drawable/drawer_item_background"/>
Also if in-case you do not want to use a selector to achieve that you can do so like this
<group android:checkableBehavior="single">
<item
android:id="#+id/nav_share"
android:icon="#drawable/ic_menu_share"
android:title="#string/menu_share" />
</group>
By wrapping the element under <group android:checkableBehavior="single"> we get a selected background.
Try the below item_background.xml in
app:itemBackground="#drawable/item_background" for NavigationView
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/rgb_red" android:state_checked="true" />
<item android:drawable="#color/rgb_red" android:state_activated="true" />
<item>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/rgb_white" />
<item android:start="-2dp"
android:top="-2dp"
android:end="-2dp">
<shape>
<solid android:color="#android:color/transparent" />
<stroke android:width="1dp" android:color="#color/rgb_pale_gray"/>
</shape>
</item>
</layer-list>
</item>
</selector>
hope it will help you

ripple drawable crashes the app on Android API 19

I am using a custom ripple drawable
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="#android:integer/config_shortAnimTime"
android:color="#android:color/white">
<item android:id="#android:id/mask">
<shape android:shape="rectangle" >
<solid android:color="#android:color/white" />
</shape>
</item>
</ripple>
but it crashes the app on API 19
android.content.res.Resources$NotFoundException: File res / drawable /
ripple_effect_square2.xml from drawable resource ID #0x7f02017d
at android.content.res.Resources.loadDrawable(Resources.java:2101)
at android.content.res.Resources.getDrawable(Resources.java:700)
at android.view.View.setBackgroundResource(View.java:15303)
Caused by: org.xmlpull.v1.XmlPullParserException: Binary XML file line # 2: invalid drawable tag ripple
at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java: 933)
at android.graphics.drawable.Drawable.createFromXml(Drawable.java: 877)
at android.content.res.Resources.loadDrawable(Resources.java: 2097)
at android.content.res.Resources.getDrawable(Resources.java: 700) 
at android.view.View.setBackgroundResource(View.java: 15303) 
What should i do to prevent crashing ?
The RippleDrawable was added in API 21, so it's not available on earlier SDKs.
You can move your drawable file to res/drawable-v21 to ensure it doesn't crash on earlier releases.
I had the same problem.
Mina Samy's answer solved my problem also.
Atef Hares asked for an alternative in older versions.
What works for me is to use a selector instead of ripple
for example:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="#ccffffff" />
</shape>
</item>
<item android:state_focused="true">
<shape android:shape="rectangle">
<stroke android:color="#android:color/white" />
</shape>
</item>
<item android:drawable="#color/playColor" />
</selector>
where
<color name="playColor">#E8EAF6</color>
Ripple is only available from Lollipop (Android API 21). Here is an example for backwards compatibility which includes states and no default background (Transparent):
Create two drawable xml files with the same name, one will be placed in the drawable-v21 folder, and the other in the normal drawable folder.
drawable-v21/ripple_red_solid.xml:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#android:color/red">
<item android:id="#android:id/mask">
<color android:color="#android:color/red" />
</item>
<item>
<selector>
<item android:state_selected="true">
<color android:color="#android:color/red" />
</item>
<item android:state_activated="true">
<color android:color="#android:color/red" />
</item>
<item android:state_focused="true">
<color android:color="#android:color/red" />
</item>
</selector>
</item>
</ripple>
drawable/ripple_red_solid.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
<shape android:shape="rectangle">
<solid android:color="#android:color/red" />
</shape>
</item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="#android:color/red" />
</shape>
</item>
<item android:state_focused="true">
<shape android:shape="rectangle">
<solid android:color="#android:color/red" />
</shape>
</item>
</selector>
And then simply use it on the view like:
<LinearLayout
...
android:background="#drawable/ripple_red_solid" />

How to apply state press for a button in android xml, when I have already used up option of style and background?

I have a num keypad that I have created using buttons and have hide my android soft keyboard.
This is how my every button looks like for different numbers
<Button
android:id="#+id/seven"
android:text="7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
style="#style/CustomStyle"
android:background="#drawable/gridlayout_border"
/>
Notice that I am using CustomStyle whose code looks like this with the filename button_style.xml
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="CustomStyle">
<item name="android:textSize">24dp </item>
<item name="android:textColor">#fdfdfd</item>
<item name="android:textStyle">bold </item>
<item name="android:padding">20dp</item>
</style>
</resources>
Also, I am using gridlayout_border as a background
gridlayout_border.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:left="-10dp" android:right="0dp" android:top="-10dp"
>
<shape android:shape="rectangle">
<!--apply button background transparent, full opacity-->
<solid android:color="#00ffffff"/>
<stroke android:color="#ffffff" android:width="2dp"/>
</shape>
</item>
</layer-list>
Since, I have used up the style and background tag in button. How can I now apply one more style/color when my button is being pressed on num keypad?
Thanks in advance
You can use selector to determine different states of a view. Something like this:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true">
<!-- Write your focused state code-->
</item>
<item android:state_pressed="true">
<!-- Write your pressed state code-->
</item>
<item>
<layer-list>
<item android:left="-10dp" android:right="0dp" android:top="-10dp"
>
<shape android:shape="rectangle">
<!--apply button background transparent, full opacity-->
<solid android:color="#00ffffff"/>
<stroke android:width="2dp" android:color="#ffffff"/>
</shape>
</item>
</layer-list>
</item>
</selector>

Android Ripple Effect Overridden by Selected State

After having been looking for a while I've not been able to find an answer to this...
I have a recycler view with items which when selected have a red background and white text (beforehand the background is white and text is black). To do this I am using a selector.
I have recently tried to add a ripple effect to this, but unless I long click on the item the background of the item goes straight to red without the ripple. I am assuming this is because the selector state state_selected overrides the ripple on sate_pressed?
Does anyone know if there is a way around this? Here is the selector code I use:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#android:color/holo_red_dark" >
<item>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:drawable="#drawable/ripple"
android:state_pressed="true"/>
<item
android:drawable="#android:color/holo_red_dark"
android:state_selected="true"/>
<item android:drawable="#android:color/white"/>
</selector>
</item>
</ripple>
Thanks in advance!
To create a selector background that has a ripple effect and shows selected status I do the following:
Start by defining your highlight color, with some transparency:
values/colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="selector_color">#660000ff</color>
</resources>
You probably want to have compatibility pre-lollipop. Put a typical old-school selector inside drawable folder:
drawable/selector_background.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/selector_color" android:state_pressed="true"/>
<item android:drawable="#color/selector_color" android:state_selected="true"/>
<item android:drawable="#android:color/transparent"/>
</selector>
And then add the following layer drawable inside drawable-v21 folder:
drawable-v21/selector_background.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<selector>
<item android:state_selected="true"
android:drawable="#color/selector_color" />
<item android:drawable="#android:color/transparent" />
</selector>
</item>
<item>
<ripple android:color="#color/selector_color">
<item android:id="#android:id/mask">
<color android:color="#android:color/white" />
</item>
</ripple>
</item>
</layer-list>
Now you can use #drawable/selector_background for your selector.
So I have another case in which I had to use selector as well as layer list for that
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/colorRipple">
<item>
<layer-list>
<item>
<shape android:shape="rectangle">
<solid android:color="#color/grey_very_light" />
</shape>
</item>
<!-- ripple color -->
<item android:bottom="1dp">
<shape android:shape="rectangle">
<solid android:color="#color/c_unread_notifications_item" />
</shape>
</item>
</layer-list>
</item>
</ripple>
</item>
<item>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/colorRipple">
<item>
<!-- ripple color -->
<layer-list>
<item>
<shape android:shape="rectangle">
<solid android:color="#color/grey_very_light" />
</shape>
</item>
<item android:bottom="1dp">
<shape android:shape="rectangle">
<solid android:color="#color/white" />
</shape>
</item>
</layer-list>
</item>
</ripple>
</item>
</selector>
This worked, for your need what you can do it just replace the item under ripple with your item shape if you don't have any layering.
Hope this helps
It will be better if you wrap your recyclerview item view in FrameLayout and set android:background="?selectableItemBackground" of FrameLayout and the child layout of FrameLayout background="#drawable/background"
background.xml
<item android:drawable="#color/red" android:state_selected="true"/>
<item android:drawable="#color/red" android:state_focused="true"/>
<item android:drawable="#color/red" android:state_pressed="true"/>
<item android:drawable="#color/white"/>
And then child layout must has attribute android:duplicateParentState="true"

How to add underline to selected side menu item in SlidingMenu?

I want to put an underline to my selected side menu item.Is there any way to put only an underline to the item name instead of highlighting the whole item?
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
<item android:drawable="your drawable when pressed" android:state_pressed="true"/>
<item android:drawable="your drawable when selected" android:state_selected="true"/>
<item android:drawable="your drawable when activated" android:state_activated="true"/>
</selector>
The above code is a simple selector from where you can make the one that you need and you also need to add android:choiceMode="singleChoice" to your listview and also add the selector listView.setSelector(R.drawable.your_selector); or you can add in xml like android:listSelector="#drawable/your_selector"
A better selector for your need would be
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
<layer-list>
<item>
<shape>
<solid android:color="#ffffff" />
</shape>
</item>
<item android:bottom="3dp">
<shape>
<solid android:color="#ff0000" />
</shape>
</item>
</layer-list>
</item>
</selector>
Hope it helps a bit.

Categories

Resources