i want to change background of my view when the state is "activated" and i want to preserve the effects(ripple) of ?attr:selectableItemBackground
. Is it possible to extend or combine selector of ?attr:selectableItemBackground
?

- 401
- 1
- 5
- 14
5 Answers
You can use a LayerDrawable
in order to draw the ripple effect drawable (?attr:selectableItemBackground
) over your activated state color.
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<selector>
<item android:state_activated="true">
<color android:color="?attr/colorPrimary"/>
</item>
<item>
<color android:color="@android:color/transparent"/>
</item>
</selector>
</item>
<item android:drawable="?attr/selectableItemBackground"/>
</layer-list>
Edit: As it's not possible to use theme attributes in an XML drawable before API 21, it seems to be better to put the ripple effect drawable as a foreground drawable, and the activated color selector drawable as a background drawable.
<View
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/yourView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:foreground="?attr/selectableItemBackground"
android:background="@drawable/activated_color_selector">
With res/drawable/activated_color_selector.xml
containing:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_activated="true">
<!-- Can't use the ?attr/colorPrimary before API 21 -->
<color android:color="@color/primaryColor"/>
</item>
<item>
<color android:color="@android:color/transparent"/>
</item>
</selector>

- 1,115
- 9
- 9
-
1This will only work on Lollipop and up... will crash with unknown class exception on Kitkat and lower devices. – Ray W Apr 06 '16 at 14:49
-
Yeah true... I just discovered that it's not possible to use theme attributes in drawable XML until Lollipop. – Nit Apr 11 '16 at 14:59
For those who only care about API >= 21 now in 2020, here's a simpler solution :
<ripple
xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?colorControlHighlight">
<!-- the ripple's color (1) -->
<!-- no `id` so our <shape> will be drawn and not just used as mask -->
<item>
<shape>
<corners android:radius="9dp" />
<solid android:color="@color/white" />
</shape>
</item>
</ripple>
(1)
If you don't overridecolorControlHighlight
in your theme, the ripple's color will be Android's default. If you do override it in your theme but want to use Android's default for a specific case use?android:colorControlHighlight
instead.

- 9,012
- 5
- 54
- 71
To change ripple color throughout the app you can ad this in your app theme
<item name="colorControlHighlight">@color/ripple</item>

- 49
- 1
-
1i don't want to change the ripple color, i want to change background color when the state is "activated" i.e. selected. – Asiat Feb 11 '16 at 05:13
-
You can add a background color and add clickable = true for ripple color – Rohit Feb 11 '16 at 10:42
Unfortunately, the only way I found is to have additional view in your layour that will emulate the selected state. Like so (works on pre-Lollipop as well):
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="?attr/listPreferredItemHeight"
android:background="?attr/selectableItemBackground">
<View
android:id="@+id/item_selected"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorControlHighlight"/>
<android.support.v7.widget.AppCompatTextView
android:id="@+id/item_title"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:textAppearance="?attr/textAppearanceListItem"/>
</FrameLayout>
Then in your adapter you set visibility of item_selected
to either View.VISIBLE
or View.GONE
, based on the need to make this particular item selected.
P.S. Obviously, this solution uses AppCompat support library, so in order to use it the following line should be added to build.gradle
file:
implementation 'com.android.support:appcompat-v7:28.0.0'

- 1,865
- 19
- 28
I solved this problem by swapping the background drawables at runtime. This code runs in onBindViewHolder
in RecyclerView.Adapter<MyViewHolder>
:
if (selected) {
itemView.setBackgroundResource(R.drawable.selected_background);
} else {
TypedArray typedArray = context.obtainStyledAttributes(
new int[]{android.R.attr.selectableItemBackground});
itemView.setBackgroundResource(typedArray.getResourceId(0, 0));
typedArray.recycle();
}
The R.drawable.selected_background
refers to the background of a selected item:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/colorAccentLight" android:state_activated="true" />
<item android:drawable="@android:color/transparent" />
</selector>
Another solution is to have two identical item types except for different backgrounds but that seems to be an overkill.

- 495
- 5
- 14