Hi so I am little confused and wondering if anyone could point me in the right direction.
Go and use Google Play Store on Lollipop and pre-lollipop
You will see on lollipop that selectable views have the ripple effect.
On pre-lollipo, you get this highlight effect.
How is this done?
At the moment in my app, I have a drawable-v21 directory that contains this selector
It basically does the ripple on top of my background
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:colorControlHighlight">
<item android:id="@android:id/mask" android:drawable="@android:color/white"/>
<item android:drawable="@color/colorAccentWith92PercentOpacity"/>
</ripple>
However, other answers say to use
android:background="?attr/selectableItemBackground"
To get the highlight effect on pre-lollipop but this overrides my background. How could i set this on top of my current background?
Also do i have to create a ripple drawable (in drawble-v21) for every kind of button in my app? How would I do this for recycler view items?
What makes this question unique
I do not want ripple for pre-lollipop I am asking how devs efficiently make their button do ripple on lollipop and a hight light effect on pre
Define colorControlHighlight
in your theme and as long you're using default appcompat-v7 buttons the highlight color should work out-of-the-box.
This is an example of how I backported Material button style with a bit of crossfade animation and shadows without using external libraries. May it help you on your way.
Provided the button will be white text over dark background (@color/control_normal
) with light highlight:
Here I'll override default button style for the whole theme:
<style name="AppTheme" parent="Base.AppTheme">
<item name="buttonStyle">@style/Widget.AppTheme.Button</item>
</style>
<!-- Some numbers pulled from material design. -->
<integer name="button_pressed_animation_duration">100</integer>
<integer name="button_pressed_animation_delay">100</integer>
Button style for Lollipop which understands theme overlays and uses ripple by default. Let's just have it color the ripple with appropriate paint:
<style name="Widget.AppTheme.Button" parent="Widget.AppCompat.Button">
<!-- On Lollipop you can define theme via style. -->
<item name="android:theme">@style/ThemeOverlay.AppTheme.Button</item>
</style>
<style name="ThemeOverlay.AppTheme.Button" parent="ThemeOverlay.AppCompat.Dark">
<!-- The magic is done here. -->
<item name="colorButtonNormal">@color/control_normal</item>
</style>
Before Lollipop it gets tricky.
<style name="Widget.AppTheme.Button" parent="Widget.AppCompat.Button">
<item name="android:background">@drawable/button_normal_background</item>
</style>
Thi is the composite drawable of the whole button.
<inset
xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="@dimen/abc_button_inset_horizontal_material"
android:insetTop="@dimen/abc_button_inset_vertical_material"
android:insetRight="@dimen/abc_button_inset_horizontal_material"
android:insetBottom="@dimen/abc_button_inset_vertical_material">
<layer-list>
<!-- Shadow. -->
<item
android:drawable="@drawable/button_shadow"
android:top="-0dp"
android:bottom="-1dp"
android:left="-0dp"
android:right="-0dp"/>
<item
android:drawable="@drawable/button_shadow_pressable"
android:top="-0dp"
android:bottom="-3dp"
android:left="-1dp"
android:right="-1dp"/>
<!-- Background. -->
<item android:drawable="@drawable/button_shape_normal"/>
<!-- Highlight. -->
<item>
<selector
android:enterFadeDuration="@integer/button_pressed_animation_duration"
android:exitFadeDuration="@integer/button_pressed_animation_duration">
<item
android:drawable="@drawable/button_shape_highlight"
android:state_focused="true"
android:state_enabled="true"/>
<item
android:drawable="@drawable/button_shape_highlight"
android:state_pressed="true"
android:state_enabled="true"/>
<item
android:drawable="@drawable/button_shape_highlight"
android:state_selected="true"
android:state_enabled="true"/>
<item android:drawable="@android:color/transparent"/>
</selector>
</item>
<!-- Inner padding. -->
<item android:drawable="@drawable/button_padding"/>
</layer-list>
</inset>
This is the shadow when not pressed.
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:bottomLeftRadius="3dp"
android:bottomRightRadius="3dp"
android:topLeftRadius="2dp"
android:topRightRadius="2dp"/>
<solid android:color="#2000"/>
</shape>
This is the extended shadow in pressed state. The result effect will look crude when you look up close but it's good enough from distance.
<selector
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="UnusedAttribute"
android:enterFadeDuration="@integer/button_pressed_animation_duration"
android:exitFadeDuration="@integer/button_pressed_animation_duration">
<item
android:state_pressed="true"
android:state_enabled="true">
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:bottomLeftRadius="5dp"
android:bottomRightRadius="5dp"
android:topLeftRadius="3dp"
android:topRightRadius="3dp"/>
<solid android:color="#20000000"/>
</shape>
</item>
<item android:drawable="@android:color/transparent"/>
</selector>
This is the main button shape.
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="@dimen/abc_control_corner_material"/>
<solid android:color="@color/control_normal"/>
</shape>
Just additional padding to be absolutely consistent with the Material button.
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@android:color/transparent"/>
<padding
android:left="@dimen/abc_button_padding_horizontal_material"
android:top="@dimen/abc_button_padding_vertical_material"
android:right="@dimen/abc_button_padding_horizontal_material"
android:bottom="@dimen/abc_button_padding_vertical_material"/>
</shape>
This is the highlight button shape drawn over normal button shape.
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="@dimen/abc_control_corner_material"/>
<solid android:color="@color/control_highlight"/>
</shape>
@color/control_highlight
can point to
@color/ripple_material_dark
- translucent white, use over dark background@color/ripple_material_light
- translucent black, use over light backgroundYou can set a background of your views in this way:
android:background="@drawable/touch_selector"
Create a version without ripple for pre lollipop: drawable/touch_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- State when a row is being pressed, but hasn't yet been activated (finger down) -->
<item android:state_pressed="true"
android:drawable="@color/grey"
/>
<!-- For ListView in SINGLE_CHOICE_MODE, it flags the active row -->
<item android:state_activated="true"
android:drawable="@color/light_green" />
<!-- Default, "just hangin' out" state. -->
<item android:drawable="@android:color/transparent" />
</selector>
Now do the same for lollipop and above,
but with ripple effect:
crete drawable-v21/touch_selector.xml
It will look like:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- State when a row is being pressed, but hasn't yet been activated (finger down) -->
<item android:state_pressed="true">
<ripple android:color="@color/grey" />
</item>
<!-- For ListView, when the view is "activated". In SINGLE_CHOICE_MODE, it flags the active row -->
<item android:state_activated="true"
android:drawable="@color/light_green" />
<!-- Default, "just hangin' out" state. -->
<item android:drawable="@android:color/transparent" />
</selector>
That's it.
Now you are having ripple effect at lollipop and above devices and highlight at pre lollipop.
Edit:
In case of using in a ListView - use created above as a background of ListView item
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With